I have a camel rest api. I was trying to create an IAM User using apache camel framework. The code is like so ->
.post("iam-create-user")
.route()
.process(new Processor(){
#Override
public void process(Exchange exchange) throws Exception {
exchange.getIn().setHeader("CamelAwsIAMUsername", "new-user");
})
.to("aws2-iam://current-user?accessKey=insert&secretKey=insert&operation=createUser")
.endRest();
I am getting this error java.lang.NullPointerException: null. What is the correct way of doing this? It shows in the camel docs to use a URL like so to("aws2-iam://test?iamClient=#amazonIAMClient&operation=createUser"). What do we put as iamClient?
The iamClient reported in the example (#amazonIAMClient) is an instance of IAMClient you'll need to put in the Camel registry with a bind name amazonIAMClient.
I think you need to specify region as aws-global for this particular component.
Maybe add the full stack trace of your error.
Related
I am trying to connect to salesforce using Apache Camel salesforce component.
Here is a very simple route I am trying to start:
#Override
public void configure() throws Exception {
from("salesforce:event/Case__e")
.to("mock:end");
}
When trying to start it I am getting an obvious error saying I did not specify a client id:
Caused by: java.lang.IllegalArgumentException: clientId must be specified
at org.apache.camel.util.ObjectHelper.notNull(ObjectHelper.java:149) ~[camel-util-3.16.0.jar:3.16.0]
at org.apache.camel.component.salesforce.SalesforceLoginConfig.validate(SalesforceLoginConfig.java:238) ~[camel-salesforce-3.16.0.jar:3.16.0]
That makes perfectly sense as according to Camel docs clentId parameter must be specified. To address this I am specifying a clientId as below:
#Override
public void configure() throws Exception {
from("salesforce:event/Case__e?clientId=xyz")
.to("mock:end");
}
When trying to start the route this time I am getting a rather strange error complaining about clientId being an unknown parameter:
Failed to resolve endpoint: salesforce://event/Case__e?clientId=xyz due to: There are 1 parameters that couldn't be set on the endpoint.
Check the uri if the parameters are spelt correctly and that they are properties of the endpoint.
Unknown parameters=[{clientId=xyz}]
Not sure what I am doing wrong and how should I address this.
Thank you in advance for your inputs.
Your problem is related to the fact that clientId is a component option so it must be configured at the component level while you try to configure it like it was a query parameter / an endpoint option which cannot work.
Depending on the runtime that you use, the way to configure a component may change but the idea remains the same.
For example, assuming that you use an application.properties to configure your application, the configuration of your salesforce component would look like this:
In application.properties
# Salesforce credentials
camel.component.salesforce.login-config.client-id=<Your Client ID>
camel.component.salesforce.login-config.client-secret=<Your Client Secret>
camel.component.salesforce.login-config.refresh-token=<Your Refresh Token>
...
Here is a salesforce example https://github.com/apache/camel-examples/blob/main/examples/salesforce-consumer/
I am developing 2 camel application :
Camel_1 application is deployable in server_1 and it need to make some rest calls to camel_2 application deployed in server_2.
Camel_1 :
public void configure() throws Exception {
from("file:C:/folder/IN")
.setBody(simple("${null}"))
.to("http://localhost:9090/camel/my-get-endpoint")
.log("Service body : ${body['filename']}")
Camel_2 :
#Override
public void configure() throws Exception {
restConfiguration()
.component("servlet")
.bindingMode(RestBindingMode.auto);
rest()
.get("/my-get-endpoint")
.route()
.outputType(String.class)
.to("mongodb:camelMongoClient?database=db&collection=myCollection&operation=findAll")
.log("Body Set ${body}")
.endRest()
}
}
Camel_2 returns body as :
[Document{{id=5ef11dd8ee96198e7bf4cb34, configured_email=abc#gmail.com, filename=[A-Z]{4} [A-Z|a-z_]{1,}((0[1-9])|(1[0-2]))((0[1-9])|(1[0-9])|(2[0-9])|(3[0-1]))_(19|20)\d{2}.(xls[mx]{1}|xls||csv)$}}]
Camel_1 also prints the same body but how do I transform this reponse so that I can pick the required fields and perform methods like ${body.size()}.
You might want to convert the BSON document MongoDB usually returns, into JSON. See if this list helps: MongoDB type conversions.
Converted the body into map and then I was able to access it.
I want to build an Apache camel application to download a Jira
issue report, parse it, and store it into a .csv file.
I'm new at Apache camel, I do believe the jira here should be an endpoint, how to setup this configuration, I want to set is as from:("Jira") to (csv file).
I believe it could be something like this:
public void configure() throws Exception {
from("jira://pullRequestComment?ProjectKey=CAMEL-0000&IssueTypeId=1&IssueSummary=title")
.process(new MyLogProcessor())
.bean(new MyTransformer(),"transformContent")
.to("file:D:/camel/output");
}
I tried the above code, I got an exception for java conversion type.
Exception:
The JIRA component returns Java objects from the JIRA REST API. You need to either:
Support passing in the object type to your processor class as a method argument
Convert the JIRA Java Object to something else, then pass into your processor
BTW- The JIRA component caches "seen" data to know what is "new" to pass into the route. For really busy JIRA servers, this looks and acts like a memory leak so you'll need to be mindful to manage that scenario
The pullRequestComment endpoint is for a producer endpoint (i.e. it can only go in to("jira:pullRequestComment?..."). Since you want to poll for new comments, you should use the newComment endpoint. So your route would look something like:
from("jira:newComment?serverUrl={host}&username={username}password={password}")
.process(new MyLogProcessor())
.bean(new MyTransformer(),"transformContent")
.to("file:D:/camel/output");
Note that this endpoint returns an object of type com.atlassian.jira.rest.client.domain.Comment, so in MyLogProcessor if you do exchange.getIn().getBody(), it will return an object of type Comment (or maybe a List if there are multiple objects, you'll have to test this).
If you want to post a pull request comment, then you can use the pullRequestComment endpoint like the following:
from("direct://some/uri/name")
.header("ProjectKey", "CAMEL-0000")
.header("IssueTypeId", 1L)
.header("IssueSummary", "title")
.to("jira:pullRequestComment?serverUrl={host}&username={username}password={password}")
.... // More processing here
Then if you invoke the route from("direct://some/uri/name"), it should post the comment that's in the exchange body.
I'm using Camel to integrate 2 systems. I have defined different routes and one of the routes consumes from a specific rabbitmq queue and send it to a REST service. Nothing fancy here, the route looks like this:
public class WebSurfingRabbitToRestRoute extends RouteBuilder{
#Override
public void configure() throws Exception {
from("rabbitmq://rabbit_host:port/Rabbit_Exchange").
setHeader("CamelHttpMethod", constant("POST")).
setHeader("Content-Type", constant("application/json")).
bean(TransformResponse.class, "transform").
to("http4://rest_service_host:port/MyRestService).
}
}
As you can see, i process every message before sending it to the rest service since i need to adjust some things. The problem comes when i find out that sometimes (i dont know how or when), the system that publish into rabbit, send 2 messages concatenated at once.
What i expect to get is a simple json like this:
[{field1:value1, field2:value2}]
What i sometimes get is:
[{field1:value1, field2:value2},{field1:value3, field2:value4}]
So when i face this scenario, the rest service im routing the message to, fails (obviously).
In order to solve this, i would like to know if there is a way to invoke a route from inside a processor. From the previous snippet of code you can see that Im calling the transform method, so the idea will be to do something like the following pseudo-code, because after the route is already fired, i cant split the events and send them both within the same route "instance", so i thought about invoking a different route that i can call from here which will send the message2 to the very same rest service.
public class TransformRabbitmqResponse {
public String transform(String body) throws Exception {
// In here i do stuff with the message
// Check if i got 2 messages concatenated
// if body.contains("},{") {
// split_messages
// InvokeDifferentRoute(message2)
//}
}
}
Do you guys think this is possible?
One option (though I am not sure this is the best option) would be to split this up into two different routes using a direct endpoint.
public class WebSurfingRabbitToRestRoute extends RouteBuilder{
#Override
public void configure() throws Exception {
from("rabbitmq://rabbit_host:port/Rabbit_Exchange")
.setHeader("CamelHttpMethod", constant("POST"))
.setHeader("Content-Type", constant("application/json"))
.bean(TransformResponse.class, "transform");
from("direct:transformedResponses")
.to("http4://rest_service_host:port/MyRestService");
}
}
And then in your transform bean, you can use camel Producer Template to publish the transformed payload(s) to your new direct endpoint (assuming you are using json?).
producerTemplate.sendBody("direct:transformedResponses", jsonString);
I have this route
from(URI_WEBSERVICE)
.convertBodyTo(Entrada.class)
.process(new ProcessorTratarWS())
.pollEnrich("ftp://10.100.8.2/entradaCamel?username=USER&password=PASSWORD&delete=true&fileName=${property.archivoRespuesta}", timeOut, new EstrategiaConfirmacion())
.to(WS_RESPONDER)
In ProcessorTratarWS() I set the value of property.archivoRespuesta and is the name of the file that the pollEnrich should donwload.
But, documentation says that "PollEnrich does not have access to the Exchange". It means the PollEnrich can't read the value of ${property.archivoRespuesta}
Are there some alternative ways to do in Camel the same thing I'm trying?
Thanks!
From http://camel.apache.org/content-enricher.html
...
Instead of using enrich you can use Recipient List and have dynamic
endpoints and define an AggregationStrategy on the Recipient List
which then would work as a enrich would do. ...
try something like:
from(URI_WEBSERVICE)
.convertBodyTo(Entrada.class)
.process(new ProcessorTratarWS())
.recipientList(simple("ftp://10.100.8.2/entradaCamel?username=USER&password=PASSWORD&delete=true&fileName=${property.archivoRespuesta}")).aggregationStrategy(new EstrategiaConfirmacion())
.to(WS_RESPONDER)
Edit:
The above code is to save file in FTP server.
If you want to poll file from the FTP server you can try
from(URI_WEBSERVICE)
.convertBodyTo(Entrada.class)
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
// logic of ProcessorTratarWS goes here
ConsumerTemplate consumer=exchange.getContext().createConsumerTemplate();
String filename=exchange.getProperty("archivoRespuesta",String.class);
Object file=consumer.receiveBody("ftp://10.100.8.2/entradaCamel?username=USER&password=PASSWORD&delete=true&fileName="+filename,timeOut);
// logic of EstrategiaConfirmacion goes here
}
})
.to(WS_RESPONDER);
Disclaimer: I have not used polling consumer much and there could be more elegant/efficient solution
You can use "simple" expression
also use "exchangeProperty" instead of "property" in the string
from(URI_WEBSERVICE)
.convertBodyTo(Entrada.class)
.process(new ProcessorTratarWS())
.pollEnrich().simple("ftp://10.100.8.2/entradaCamel?username=USER&password=PASSWORD&delete=true&fileName=${exchangeProperty.archivoRespuesta}")
.timeout(timeOut)
.aggregationStrategy(new EstrategiaConfirmacion())
.to(WS_RESPONDER)