I am new to using Apache camel with Spring boot and try to implement a basic route in which, I want to filter out first whether the file has json contents or xml contents and based upon it, I want to save the file in some specific folder.
I make my service instance up and then hit its post endpoint using postman with JSON content. My service saves that file to some folder location with txt extension. I have created the route in the service which picks up the file and checks if it is not empty, it will transform the contents in to XML format and store it to some folder. Route for this thing is below:
public class OutboundRoute extends RouteBuilder {
Predicate p1=body().isNotNull();
Predicate p2=body().isNotEqualTo("");
Predicate predicateGroup=PredicateBuilder.and(p1,p2);
String inputFilePath="file:C:\\Users\\StorageFolder\\Input?noop=true";
String outputFilePathForJson="file:C:\\Users\\StorageFolder\\JsonFolderOutput?delete=true";
@Override
public void configure() throws Exception {
from(inputFilePath)
.routeId("readingJsonFromFile")
.choice()
.when(predicateGroup)
.log("Before converting to XML: ${body}")
.unmarshal().json(JsonLibrary.Jackson, Message.class)
.marshal().jacksonXml(true)
.log(LoggingLevel.INFO, "Payload after converting to xml = ${body}")
.to(outputFilePathForJson)
.otherwise()
.log("Body is Empty!!")
.end();
}
}
Now I want to implement this thing for xml also for better understanding. I want that I can hit my service using postman with either XML or JSON content. The route should pick the file and check it. If it has XML contents, route should convert its contents to JSON and store it to JSON folder but if it has JSON contents, route should convert its contents to XML and store it to XML folder. I need help with this thing.
Main thing is that when I hit the service using postman, service will always store the file with txt extension only. So, I need help with a way to find that content of file is of JSON format or XML format.
Also, I tried finding some content about learning apache camel but everywhere found basic tutorials only. Can someone recommend some platform where I can learn how to write complex routes?
CodePudding user response:
Personally, I would use something like Apache Tika to make an educated guess on the file type and slap a Content-Type in the camel headers. Then you can handle any number of types of files by using the Choice Enterprise Integration Pattern. This relies heavily on the Camel Direct Component, which I suggest learning about as it often used in Camel development for composable routes. This would looks something like the following:
from(inputFilePath)
.process(exchange -> {
Metadata metadata = new Metadata();
File f = exchange.getIn().getBody(File.class)
String mimetype = tika.getDetector().detect(TikaInputStream.get(f, metadata), metadata);
exchange.setHeader("Content-Type", mimetype)
})
.to("direct:content-type-chooser")
// route that just determines routing using the
from("direct:content-type-choose")
.choice()
.when(header("Content-Type").contains("application/xml")).to("direct:process-xml")
.when(header("Content-Type").contains("application/json")).to("direct:process-json")
.otherwise()
.to("direct:unsupported-type")
// route for processing xml
from("direct:process-xml")
...
// route for processing json
from("direct:process-json")
...
// route for giving an error because we don't support it, or doing whatever you do (like move it to another folder for later processing)
from("direct:unsupported-type")
...
Once you have gotten to a specific type, you can leverage Marshallers and Unmarhallers.
Unfortunately, the only way to learn camel is to read the docs (thoroughly) and use it. Because camel is really just an extension of java, using standardized communication patterns, it really can do anything, so the amount that it can do could fill the internet. This problem is prevalent in all frameworks. For example, if you learn Spring, there are a lot of "Hello World" projects, but not a ton that do really complicated things. For that, you might have to scour GitHub codebases or do really targeted google searches.
CodePudding user response:
I won't say its a good answer but an easy alternative I would say.
What I did is, I created a processor which will check first character of file and if its "{", then its json and if its "<", then its XML. So, after detecting, I would add a header to camel route exchange as "Type": json or xml or unknown
And using camel's "simple" language,I will check the header and based on that, in the route, I will do the processing. I am adding below files for better reference.
Predicates used in route:
private Predicate notNull=body().isNotNull();
private Predicate notEmpty=body().isNotEqualTo("");
private Predicate checkEmptyFile=PredicateBuilder.and(notNull,notEmpty);
private Predicate checkIfJsonContents=header("Type").isEqualTo("json");
private Predicate checkIfXmlContents=header("Type").isEqualTo("xml");
private Predicate checkIfFileHasJsonContents=PredicateBuilder.and(checkEmptyFile,checkIfJsonContents);
private Predicate checkIfFileHasXmlContents=PredicateBuilder.and(checkEmptyFile,checkIfXmlContents);
Route:
from(inputFilePath)
.routeId("readingJsonFromFile")
.routeDescription("This route will assign a file type to file based on contents and then save it in different folder based on contents.")
.process(fileTypeDetectionProcessor)
.log("Added file type to header as: ${header.Type}")
.choice()
.when(checkIfFileHasJsonContents)
.log("Payload before converting to XML: ${body}")
.unmarshal().json(JsonLibrary.Jackson, Message.class)
.marshal().jacksonXml(true)
.log(LoggingLevel.INFO, "Payload after converting to xml = ${body}")
.to(outputFilePathForXml)
.when(checkIfFileHasXmlContents)
.log("Payload before converting to JSON: ${body}")
.unmarshal().jacksonXml(Message.class,true)
.marshal().json(true)
.log(LoggingLevel.INFO, "Payload after converting to JSON = ${body}")
.to(outputFilePathForJson)
.otherwise()
.log("Unreadable format or empty file!!")
.to(outputFilePathForBadFile)
.end();
Processor:
public class FileTypeDetectionProcessor implements Processor {
@Override
public void process(Exchange exchange) throws Exception {
if(exchange.getIn().getBody(String.class).startsWith("{"))
exchange.getIn().setHeader("Type","json");
else if(exchange.getIn().getBody(String.class).startsWith("<"))
exchange.getIn().setHeader("Type","xml");
else
exchange.getIn().setHeader("Type","unknown");
}
}