I am pretty new with Camel. I have been trying to fetch a data from http source.
Here's my code:
from("timer://runOnce?repeatCount=1")
.to("http4://webservice.com/example.xml")
.process(new structureXML())
.to("mock:resource")
.stop();
And:
class structureXML implements Processor {
public void process(Exchange httpExchange) throws Exception {
String httpres = httpExchange.getIn().getBody(String.class);
String[] lines = httpres.split("\n");
Pattern p = Pattern.compile("<Map Key='(.+)' Value='(.+)'/>");
HashMap<String, Integer> mapdata = new HashMap<String, Integer>();
for(String line : lines) {
Matcher m = p.matcher(line);
if(m.find())
mapdata.put(m.group(1), Integer.parseInt(m.group(2)));
}
httpExchange.getIn().setBody(mapdata);
}
}
Well the example works right but I want to know about the possible ways to further improve this situation(e.g xml processing using xpath and etc), also I want to know about the ways which I can store the java object inside the message so I can use it in another route(e.g: direct:resource instead of mock)
About java objects:
More information can be found here: http://camel.apache.org/data-format.html
JAXB
XStream
BeanIO
JiBX
XmlBeans
These data formats will be very useful for transforming XML to POJO.
I recomend you to try BeanIO (detailed documentation, many examples, etc).
About Xpath:
it's hard to tell anything specified without web-service response.
Example:
setBody().xpath("/soap:Envelope/soap:Body/s:insertResponse/s:data",
XmlNamespaces.getNamespace()).
About your example:
You usually need to set a lot of properties and header (before http request), so it worked fine. Example:
setProperty(Exchange.CONTENT_TYPE).constant("application/soap+xml").
setProperty(Exchange.CONTENT_ENCODING).constant("gzip").
setProperty(Exchange.CHARSET_NAME).constant("utf-8").
setHeader(Exchange.CONTENT_TYPE).exchangeProperty(Exchange.CONTENT_TYPE).
And I don't see creating the request to web-service. It is easy to do with the help of velocity (http://camel.apache.org/velocity.html), or, maybe, using SOAP date format (http://camel.apache.org/soap.html).
You can use jetty (http://camel.apache.org/jetty.html) instead of http4 (for me it's easier)
Related
I'm not going to lie I'm really bad at making regular expressions. I'm currently trying to parse a text file that is giving me a lot of issues. The goal is to extract the data between their respective "tags/titles". The file in question is a .qbo file laid out as follows personal information replaced with "DATA": The parts that I care about retrieving are between the "STMTTRM" and "/STMTTRM" tags as the rest I don't plan on putting in my database, but I figured it would help others see the file content I'm working with. I apologize for any confusion prior to this update.
FXHEADER:100
DATA:OFXSGML
VERSION:102
SECURITY:NONE
ENCODING:USASCII
CHARSET:1252
COMPRESSION:NONE
OLDFILEUID:NONE
NEWFILEUID:NONE
<OFX>
<SIGNONMSGSRSV1><SONRS>
<STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY></STATUS>
<DTSERVER>20190917133617.000[-4:EDT]</DTSERVER>
<LANGUAGE>ENG</LANGUAGE>
<FI>
<ORG>DATA</ORG>
<FID>DATA</FID>
</FI>
<INTU.BID>DATA</INTU.BID>
<INTU.USERID>DATA</INTU.USERID>
</SONRS></SIGNONMSGSRSV1>
<BANKMSGSRSV1>
<STMTTRNRS>
<TRNUID>0</TRNUID>
<STATUS><CODE>0</CODE><SEVERITY>INFO</SEVERITY></STATUS>
<STMTRS>
<CURDEF>USD</CURDEF>
<BANKACCTFROM>
<BANKID>DATA</BANKID>
<ACCTID>DATA</ACCTID>
<ACCTTYPE>CHECKING</ACCTTYPE>
<NICKNAME>FREEDOM CHECKING</NICKNAME>
</BANKACCTFROM>
<BANKTRANLIST>
<DTSTART>20190717</DTSTART><DTEND>20190917</DTEND>
<STMTTRN><TRNTYPE>POS</TRNTYPE><DTPOSTED>20190717071500</DTPOSTED><TRNAMT>-5.81</TRNAMT><FITID>3893120190717WO</FITID><NAME>DATA</NAME><MEMO>POS Withdrawal</MEMO></STMTTRN>
<STMTTRN><TRNTYPE>DIRECTDEBIT</TRNTYPE><DTPOSTED>20190717085000</DTPOSTED><TRNAMT>-728.11</TRNAMT><FITID>4649920190717WE</FITID><NAME>CHASE CREDIT CRD</NAME><MEMO>DATA</MEMO></STMTTRN>
<STMTTRN><TRNTYPE>ATM</TRNTYPE><DTPOSTED>20190717160900</DTPOSTED><TRNAMT>-201.99</TRNAMT><FITID>6674020190717WA</FITID><NAME>DATA</NAME><MEMO>ATM Withdrawal</MEMO></STMTTRN>
</BANKTRANLIST>
<LEDGERBAL><BALAMT>2024.16</BALAMT><DTASOF>20190917133617.000[-4:EDT]</DTASOF></LEDGERBAL>
<AVAILBAL><BALAMT>2020.66</BALAMT><DTASOF>20190917133617.000[-4:EDT]</DTASOF></AVAILBAL>
</STMTRS>
</STMTTRNRS>
</BANKMSGSRSV1>
</OFX>
I want to be able to end with data that looks or acts like the following so that each row of data can easily be added to a database:
Example Parse
As David has already answered, It is good to parse the POS output XML using Java. If you are more interested about about regex to get all the information, you can use this regular expression.
<[^>]+>|\\n+
You can test in the following sites.
https://rubular.com/
https://www.regextester.com/
Given this is XML, I would do one of two things:
either use the Java DOM objects to marshall/unmarshall to/from Java objects (nodes and elements), or
use JAXB to achieve something similar but with better POJO representation.
Mkyong has tutorials for both. Try the dom parsing or jaxb. His tutorials are simple and easy to follow.
JAXB requires more work and dependencies. So try DOM first.
I would propose the following approach.
Read file line by line with Files:
final List<String> lines = Files.readAllLines(Paths.get("/path/to/file"));
At this point you would have all file line separated and ready to convert the string lines into something more useful. But you should create class beforehand.
Create a class for your data in line, something like:
public class STMTTRN {
private String TRNTYPE;
private String DTPOSTED;
...
...
//constructors
//getters and setters
}
Now when you have a data in each separate string and a class to hold the data, you can convert lines to objects with Jackson:
final XmlMapper xmlMapper = new XmlMapper();
final STMTTRN stmttrn = xmlMapper.readValue(lines[0], STMTTRN.class);
You may want to create a loop or make use of stream with a mapper and a collector to get the list of STMTTRN objects:
final List<STMTTRN> stmttrnData = lines.stream().map(this::mapLine).collect(Collectors.toList());
Where the mapper might be:
private STMTTRN mapLine(final String line) {
final XmlMapper xmlMapper = new XmlMapper();
try {
return xmlMapper.readValue(line, STMTTRN.class);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
I am fairly new to Freemarker and to template engine in general.
Basicly I want to be able to generate two XML files (from two different templates) using java methods to feed data to the template.
For example:
myTemplate1.ftl contain an opening and closing "res" tag with getRes() method as value (return 1 for exemple)
myTemplate2.ftl contain an opening and closing "result" tag and takes getResult() method as value (return 2 for exemple)
How can I write one class Main to process this without being specific (I do not want to write line per line, because then it would be pointless to create an engine)
Can you please help me understand how it work through an example if possible ?
Regards
EDIT with all the new informations :
#fustaki This is very frustrating. It seems I need to go step by step to understand what I'm doing. So... Here is a very dumb example of where I am :
template1.ftl
<Email>${item.getEmail()}</Email><Language>${item.getLanguage()}</Language>
FillMyTemplate1.java
public String getEmail(){ return "test#test.com" }
public String getLanguage(){ return "EN" }
I am using a property file in order to use introspection : prop.properties which contain :
template1=fr.freemarker.test.xml.FillMyTemplate1
MainTest.java
public static void main(String[] args) throws Exception {
Properties prop = new Properties();
InputStream input = new FileInputStream("prop.properties");
prop.load(input);
Class<?> classe = Class.forName(prop.getProperty(args[0])); //where args[0] is "template1"
Configuration config=new Configuration();
config.setClassForTemplateLoading(MainTest.class, "templates");
config.setObjectWrapper(new DefaultObjectWrapper());
Template template=config.getTemplate(args[0]+".ftl");
Map<String, Object> dataModel = new HashMap<String, Object>();
Writer consoleWriter = new OutputStreamWriter(System.out);
dataModel.put("item", classe.newInstance());
template.process(dataModel, consoleWriter);
}
And the result : <Email>test#test.com</Email><Language>EN</Language>
In order to understand what you said, I need to know how a "data-provider" would look like in my case ? How can I get ride of this "item" in my map ? I understand the principle but not the technical solution...
Your Main process is in charge of producing the data (List, Map or other structured object) and templates will use the data to render your XMLs.
The tags used in the templates are independent from the data inside them.
Example where data are stored in a List that can be retrieved with a getItems() or in general is accessible from the freemarker engine.
<?xml>
<res>
<#list items as item >
<item>${item}</item>
</#list>
</res>
You can create as much templates (views) as you want using the same List items.
I hope this clarify your troubles.
here is good example of freemarker. this application generate spring mvc crud operation
using a freemarker template.
springmvcfreemarker
I have a MarkLogic XQuery eval call that returns a lists of strings. I use the below code to process the results. I have another call that returns a list of Json Documents but I can't see how to get EvalResult to give me a JsonDocument document. How do I change the below code to process Json Documents?
public static ArrayList<String> getStringList(DatabaseClient client, String query)
{
ArrayList<String> strings = new ArrayList<String>();
ServerEvaluationCall eval = client.newServerEval();
EvalResultIterator eri = eval.xquery(query).eval();
while (eri.hasNext())
{
EvalResult er = eri.next();
String s = er.getString();
strings.add(s);
}
return strings;
}
First, let me suggest that you only use eval as a last resort as it may open a security hole. Injection attacks aren't possible if you never send code from the client to be executed on the server. Start first with the out-of-the-box features, and if those aren't enough, consider writing a resource extension instead of using eval. Two examples are ResourceExtension and JavascriptResourceExtension.
But to answer your question, change this:
String s = er.getString();
to this:
JacksonHandle handle = er.get(new JacksonHandle());
JsonNode json = handle.get();
or this shortcut:
JsonNode json = er.getAs(JsonNode.class);
For a complete example, see handling of myArray and myObject EvalTest.evalAndInvokeXQuery (and of course, runAndTestXQuery) and evaltest.xqy.
These Jackson handles work the same whether you're getting JSON results from a document read, search, or eval. You can read more about the io shortcuts here. For more sample code with Jackson, see JacksonHandleExample, JacksonHandleTest, JacksonStreamTest, and JacksonDatabindTest.
I am new to Apache Camel and using Java DSL. I want to send a image file to different end points by splitting it using image processing tool. What are all the components do I need to use to achieve that and also I need to send the split images to one more end point.
You should take a look at the chapter "Using a Pojo to do the splitting" from http://camel.apache.org/splitter.html
Example for your needs as far as i understood for the pojo:
public List<Message> splitMessage(Exhange exchange) {
List<Message> answer = new ArrayList<Message>();
File inputFile = exchange.getIn().getBody(File.class);
List<YourObject> parts = yourSplittingOfTheFile(inputFile);
for (YourObject part : parts) {
DefaultMessage message = new DefaultMessage();
message.setBody(body);
answer.add(message);
}
return answer;
}
Afterwards you can send each part to one or more endpoints in your split block.
kind regards,
soilworker
I asked something like this previously, but upon re-reading my original post, it was not easy to understand what I was really asking. I have the following situation. We have (or at least I'm trying to get working) a custom file upload procedure that will take in the file, a set number of 'known' metadata values (and they will always be there), as well as potentially an unknown number of additional metadata values. The service that exists currently uses the Jersey framework (1.16)
I currently have both client and server code that handles dealing with the file upload portion and the known metadata values (server code below)
#POST
#Path("asset/{obfuscatedValue0}/")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public UUID uploadBlob(#PathParam("obfuscatedValue0") Integer obfuscatedValue0,
#FormDataParam("obfuscatedValue1") String obfuscatedValue1,
#FormDataParam("obfuscatedValue2") String obfuscatedValue2,
#FormDataParam("obfuscatedValue3") String obfuscatedValue3,
#FormDataParam("obfuscatedValue4") String obfuscatedValue4,
#FormDataParam("obfuscatedValue5") String obfuscatedValue5,
#FormDataParam("file") InputStream uploadedInputStream) {
.....
}
...and excerpt of client code:
Builder requestBuilder = _storageService
.path("asset")
.path(obfuscatedValue0.toString())
.type(MediaType.MULTIPART_FORM_DATA)
.accept(MediaType.APPLICATION_JSON);
FormDataMultiPart part = new FormDataMultiPart()
.field("file", is, MediaType.TEXT_PLAIN_TYPE) // 'is' is an inputstream from earlier in code.
.field("obfuscatedValue1", obfuscatedValue1)
.field("obfuscatedValue2", obfuscatedValue2)
.field("obfuscatedValue3", obfuscatedValue3)
.field("obfuscatedValue4", obfuscatedValue4)
.field("obfuscatedValue5", obfuscatedValue5);
storedAsset = requestBuilder.post(UUID.class, part);
However, I need to pass a map of additional parameters that will have an unknown number of values/names. From what I've seen, there is no easy way to do this using the FormDataParam annotation like my previous example.
Based upon various internet searches related to Jersey file uploads, I've attempted to convert it to use MultivaluedMap with the content type set to "application/x-www-form-urlencoded" so it resembles this:
#POST
#Path("asset/{value}/")
#Consumes("application/x-www-form-urlencoded")
public UUID uploadBlob(#PathParam(value), MultivaluedMap<String,String> formParams) {
....
}
It's my understanding that MultivaluedMap is intended to obtain a general map of form parameters (and as such, cannot play nicely together in the same method bearing #FormDataParam annotations.) If I can pass all this information from the Client inside some sort of map, I think I can figure out how to handle parsing the map to grab and 'doMagic()' on the data to get what I want done; I don't think I'll have a problem there.
What I AM fairly confused about is how to format the request client-side code when using this second method within the jersey framework. Can anyone provide some guidance for the situation, or some suggestions on how to proceed? I'm considering trying the solution proposed here and developing a custom xml adapter to deal with this situation, and sending xml instead of multipart-form-data but I'm still confused how this would interact with the InputStream value that will need to be passed. It appears the examples with MultivaluedMap that I've seen only deal with String data.