How do I set CSV header in camel DSL? - apache-camel

I have one CSV file without header which is containing two value like
"lenovo","30000"
I want to set header in first row using camel DSL and pass it to another route, header is like:
"laptop","price"
My DSL route:
from("file:...?fileName=file1.csv&noop=true")
//Something I want to include string like this
.addLineInBody("laptop"+"price").append("\n")
.to("file:../?fileName=output.csv");
How can I do this in camel DSL?

I do not fully understand your header-problem. If you want to just prepend the CSV file with a static header a save it again as CSV you could simply use a Java bean to prepend the message body.
If you want to convert CSV to a data structure or vice versa you should check out the Camel CSV documentation: http://camel.apache.org/csv.html
Update:
You can write a java bean like this. The important part is the #Body Camel annotation to inject the message body into the method. See http://camel.apache.org/parameter-binding-annotations.html for more information about this.
Do the body manipulation as you like.
public class CsvHeaderEnricher {
public String enrichCsvHeader(#Body String messageBody) {
String enrichedBody = "YourHeader" + messageBody;
return enrichedBody;
}
}
Then you can call the bean in your route like this:
from("file:...?fileName=file1.csv&noop=true")
.bean(new CsvHeaderEnricher())
.to("file:../?fileName=output.csv");
You can also register the bean in the Spring context, autowire it into the Route class and use an instance variable instead of new
As long as your bean contains only one method, you don't need to tell Camel what method to use

Related

How to dynamically return a from endpoint in apache camel DSL

Here is my code
from("google-pubsub:123:subscription1?maxMessagesPerPoll=3 & concurrentConsumers=5" ).routeId("myroute")
.process(new ProducerProcessor())
to("google-pubsub:123:topic1")
;
In my code above ,the from channel I want to make it generic.Basically it should be able to consume data from good-pubsub or may be from a file or from a JMS queue.Hence depending upon a parameter I want to return
a different from channel.Something like below
private RouteDefinition fromChannel(String parameter) {
if (parameter is "google" then
return from("google-pubsub:123:subscription1?maxMessagesPerPoll=3 & concurrentConsumers=5" )
if (parameter is "file" then
return from(/my/fileFolder/)).split(body().tokenize("\n")).streaming().parallelProcessing();
}
I tried this but I am getting null pointer exception in the fromChannel method.Please let me know if you have better ideas.
Rewrite based on comment
You can for example create a (static) template route for every input type and generate the routes based on a configured endpoint list.
I described such an endpoint configuration and route generation scenario in this answer.
Like this you can generate the split part for every file route and any other specialty for other route types.
All these input routes are routing at their end to a common processing route
.from(pubsubEndpoint)
.to("direct:genericProcessingRoute")
.from(fileEndpoint)
.split(body()
.tokenize("\n"))
.streaming()
.parallelProcessing()
.to("direct:genericProcessingRoute")
.from("direct:genericProcessingRoute")
... [generic processing]
.to("google-pubsub:123:topic1")
The multiple input (and output) routes around a common core route is called hexagonal architecture and Camel fits very well into this.

How to Pass POJO over JMS Queue in Apache Camel

I am relatively new to Jboss Fuse & Apache Camel. I poll a directory for specific XML files (using file filter) and extract info from XML content and save it in POJO, which then needs to be sent over JMS Queue (databaseQueue) along with the XML file to a route where I need to extract the params from POJO and insert in Database. But I am unable to pass the POJO over JMS queue to be able to retrieve in another route. I can't set the POJO in body as the original payload will be lost. Please help. Below is the sample route.
<route id="fileRoute">
<from uri="file:{{PFlowIn_AEROW}}?delay={{PFlowScanDelay}}&filter=#fileFilter&delete=true"/>
<process ref="saveFlowParamsInPOJO"/>
<recipientList>
<simple>activemq:queue:databaseQueue, activemq:queue:messageArchiveQueue, activemq:queue:XmlValidationQueue</simple>
</recipientList>
</route>
As far as I know you can only set one Object in message body, however you have two options.
Maybe you can deal with an object that contains the XML and your POJO.
Another option is to try to add the POJO to the message headers. Try to add it in your Processor step and the retrieve it from the other side.
exchange.getIn().setHeader("myPOJO", POJOvalue);
Edit:
As #BeenaRautela indicates, the second option proposed is not valid because headers only accepts non-object data type.
Another options are:
Send the POJO in the message body and try to send the XML as String in a header.
Store the POJO params in a Map and set it in a header.
Convert your POJO into data-interchange format (e.g. json) and save into header
Convert POJO to json string
Save json string into message header
Convert json string to POJO or map
You could import json library which are available in apache camel json component and then perform marshal/unmarshal.
If you wish to convert your POJO within your bean, you may also try Jackson ObjectMapper class to do conversion.
// Convert from POJO to json String
ObjectMapper objectMapper = new ObjectMapper();
String pojoAsString = objectMapper.writeValueAsString(yourPojo);
// Convert from json String to POJO
YourPojo yourPojo = objectMapper.readValue(pojoAsString , YourPojo.class);
// convert from json String to map
Map<String, Object> map = objectMapper.readValue(pojoAsString , new TypeReference<Map<String,Object>>(){});
Source of above ObjectMapper examples

Spring + Angular + JAR Build with Command Line Parameter

I am building a UI into a JAR for Spring Server. I have a bunch of Angular JS pages. I want to pass in a command line argument to my jar that tells it where the API server is like so:
java -jar application.jar --api=http://ip:9000
So my application.properties file has:
url=${api:http://localhost:9000}
The way I am currently doing is it just having a hardocoded js config file and on each of my .html pages:
<script src="../js/appName/config.angular.js"></script>
Which contains:
var configData = {
url:"http://localhost:9000"
};
And called in each file:
$scope.apiUrl = configData.url;
How do I tap into the applications.properties file that I can override with my JAR command line parameter during runtime vs. the way it has been coded now.
When you pass a value from command line and the same property name is present in properties file then spring boot overrides the value from command line. So to achieve what you want do something like this
In application.properties
#this is default value
app.url=localhost:8080
Create a class to map the properties value or you can use existing class or something else based on your project structure.
#Component
public class Sample {
#Value("${app.url}")
private String url;
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}
Now when your execute a jar with argument --app.url="someserver:9090" the value will be overriden and you can use this value anywhere.
Note it will also work if you try to access the properties value directly in jsp using expression.
Try it, it works. I have used the same thing in my latest project which is a composite microservices and each component need each others url.
[Edit]
Reference : http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
Am I getting it right: The client part is delivered by the application? So the part of the last sentence 'during runtime' has more the meaning of 'bootstrap/initial loading', right? One (old school) approach is to provide the entry html (e.g. index.html) through the application (a simple template engine) and provide the needed information with a setter in a JS config object:
// pseudo js code with thymeleaf
<script th:inline="javascript">
/*<![CDATA[*/
myConfig.url = [[${#httpServletRequest.remoteHost}]];
/*]]>*/
</script>
This is just a sample that will only set the remote host name but I think you get the idea.
Side note: I still don't really get why do you have to set this. If the application contains the client code, why do you work with absolute URLs for remote calls? (Disclaimer: I have only experience in Angular(2) and not with AngularJS)

Possible to initialize a bindy (Apache Camel DataFormat - FixedLength and use it in the same route

My input file consists of several type of FixedLengthRecord, so I have lots of FixedLengthDataFormat to unmarshal each post.
I split the body per row
for the first I should realize which DataFormat I should use, and create an object
Then unmarshal
Something like this one:
from(myURI)
.split().tokenize("\n")
.process(initializeMyBindyDataFormat)
.unmarshal(bindy)
.end();
But my problem is, I get NPE for that bindy object when I initilize it via a process.
But if I create a bindy object before my route definition (before from) it will be work fine. My bindy object is depended on body and I cannot initialize it before route definition.
Actually Apache Camel process initialization of bindy object before starting the route
The answer is using .inout
Since I want to have unmarshalling in another route, a simple example should be as below:
from(myURI)
.split().tokenize("\n")
.inout("direct:unmarshalSpecificRow")
.end();
from(direct:unmarshalSpecificRow")
.choice()
.when(firstPredicate)
unmarshal(new BindyFixedLengthDataFormat(package1)
.when(secondPredicate)
unmarshal(new BindyFixedLengthDataFormat(package1)
.when(thirdPredicate)
unmarshal(new BindyFixedLengthDataFormat(package1)
.otherwise()
.throwException(new IllegalArgumentException("Unrecognised post")
.end();
Thanks jakub-korab for his help.
In this case I think it is better to divide your processing in two seps.
A main route which receives the different data. Here you define the predicate rules that determine what kind of body it is. Check the start of the body, or something that determines it is of this type or that. Add a choice() when() and based on which predicate gets set to true set it to separate route.
In the secondary routes add the specific bindy format and do your marshal/unmarshal work.
An example from the the documentation:
Predicate isWidget = header("type").isEqualTo("widget");
from("jms:queue:order")
.choice()
.when(isWidget).to("bean:widgetOrder")
.when(isWombat).to("bean:wombatOrder")
.otherwise()
.to("bean:miscOrder")
.end();
http://camel.apache.org/predicate.html

Resteasy: How does json extension get extracted from /customers.json

I don't understand how the below class is able to recognize the request /customers.json as the /customers path and able to extract and extract the json extension. There is no path parameters.
"Consider this
JAX-RS resource class:
#Path("/customers")
public class CustomerResource
{
#GET
#Produces("application/xml")
public Customer getXml() {...}
#GET
#Produces("application/json")
public Customer getJson() {...}
}
For this CustomerService JAX-RS resource class, if a request of GET /custom
ers.json came in, the JAX-RS implementation would extract the .json suffix and remove
it from the request path. It would then look in its media type mappings for a media
type that matched json. In this case, let’s say json mapped to application/json. It
would use this information instead of the Accept header and dispatch this request to
the getJson() method."
I got the official answer from author: "The specification does not define a facility for this, but most JAX-RS implementations support it."

Resources