Bindy paddingChar - apache-camel

In my Bindy model I would like to set a paddingChar on one field. I saw in the documentation that with a #Fixed-length record I can add a paddingChar attribute but with a #CsvRecord it seems not to be the possible ?
This code doesn't pad field mandant with "0":
#CsvRecord(separator = ";", generateHeaderColumns=true)
public class Unity{
#DataField(pos = 1, length = 3, paddingChar = '0') String mandant;
...

According to the Camel documentation, you could use the pattern attribute for Double, Integer, Float, Short, Long, and BigDecimal fields. The format is defined according to java.text.DecimalFormat:
#DataField(pos = 1, pattern = "000")
Float mandant;
EDIT:
pattern is ignored (at least for Camel 2.13.1), if the locale is not set (a kind of a bug or at least an undocumented feature...). Thus, do the following:
final BindyCsvDataFormat bindy = new BindyCsvDataFormat(Unity.class);
bindy.setLocale(Locale.US.getISO3Country());
EDIT:
I opened a Jira issue as I think this should be fixed: CAMEL-7578
EDIT:
CAMEL-7578 is fixed for Camel versions 2.12.5, 2.13.3, and 2.14.0.

Related

Apache Camel Bindy Unmarshall vs Marshall is different

I'm working with a piece of fixed length data that is in a weird format. Essentially its 10 characters, but the first one indicates the sign. I was able to unmarshal the data as an integer using the below configuration, but when marshaling back I need to get the data in the original format.
I think the issue is the pattern appears to only be used when unmarshalling, as I changed it to something completely invalid and it doesn't change the marshalled results.
I also tried the following, which add the leading zeros, but I also need the sign character added back.
#field:DataField(pos = 1, length = 10, pattern = "+0", align = 'R', paddingChar='0')
Data
+000000746
#FixedLengthRecord
#Link
data class Row(
#field:DataField(pos = 1, length = 10, pattern = "+0")
val messageBodyLength: Int? = null
)
// All of the routes are direct:
// First unmarshal the data
from(UNMARSHALL_ENDPOINT_URI)
.unmarshal()
.bindy(BindyType.Fixed, Row::class.java)
.to(UNMARSHALL_RESULT_MOCK_ENDPOINT_URI)
sendBody(UNMARSHALL_ENDPOINT_URI, "+000000746")
// returns a Row with messageBodyLength set to 746 as expected.
from(MARSHALL_ENDPOINT_URI)
.marshal()
.bindy(BindyType.Fixed, Row::class.java)
.convertBodyTo(String::class.java)
.to(MARSHALL_RESULT_MOCK_ENDPOINT_URI)
sendBody(MARSHALL_ENDPOINT_URI, Row(messageBodyLength=746))
// Returns " 746"
// Expected "+000000746"
Thanks!
Found the issue. The pattern fields for numbers need to have a locale specified.
camel:
dataformat:
bindy-fixed:
locale: default

EOF Error Parsing Manchester Syntax in OWL-API

I have an API that receive a JSON document with classes, properties and axioms of an ontology. The file looks like this:
{
"id": "myontologyid",
"outformat": "OWL",
"ontoclass": ["Person", "Man", "Woman", "Animal", "Rational", "Arm"],
"ontoaxioms": ["Man subClassOf (Person)", "Person EquivalentTo: (Man OR Woman)", "hasBrother max 2 xsd:integer"],
"ontoproperties": ["hasPart", "isBrotherOf", "hasBrother"]
}
The ontoaxioms key is an array with all the axioms of the ontology. The values of this array MUST be in Manchester syntax as I will use the ManchesterOWLSyntaxParser to parse.
When I try to parse this code, I get the following error on hasBrother max 2 xsd:integer axiom:
[apache-tomcat-8.5.69-2]: org.semanticweb.owlapi.manchestersyntax.renderer.ParserException: Encountered |EOF| at line 1 column 29. Expected one of:
SubClassOf:
or
and
DisjointWith:
EquivalentTo:
I believe the Manchester syntax is incorrect. But I couldn't find any reference or documentation of OWL-API which indicates how to use it. Is there some?
Below is part of my code which tries to parse the axioms:
ManchesterOWLSyntaxParserImpl parser = (ManchesterOWLSyntaxParserImpl) OWLManager.createManchesterParser();
parser.setOWLEntityChecker(entityChecker);
try {
for (int i = 0; i < this.axiomas.length(); i++) {
parser.setStringToParse(this.axiomas.getString(i));
owlOntology.addAxiom(parser.parseAxiom());
}
} catch (Exception e) {
System.out.print(e.toString());
return null;
}
The questions are:
How to solve this EOF error?
How to insert correctly Manchester Syntax into OWL-API?
Where can I find some documentation on how to use Manchester Syntax to parse ontologies?
Many thanks in advance.
Your use of OWLAPI classes appears correct. The problem with the input that something else is expected to follow, i.e., that's not a full axiom.
Is the intent to say that hasBrother can only appear twice for an individual and has integer range?
As it happens, there's a unit test in the OWLAPI contract module that uses this string as input for parsing:
String in = "p max 1 owl:real";
ManchesterOWLSyntaxParser parser = OWLManager.createManchesterParser();
parser.setStringToParse(in);
OWLClassExpression cl = parser.parseClassExpression();
The string has the same format as what you're trying to parse, and it gives a class expression, not an axiom - specifically, a qualified max cardinality restriction for a data property. This can be the superclass or the subclass in a subclass axiom, for example, but the rest of the axiom is not present.

Camel Bindy return 0 instead of null (empty)

If the input data is null, when marshaling using my Bindy model (elToCSV) :
#DataField(pos = 7) int nbRoom;
and route as follow:
from("direct:start").bean(ELProcessor.class,"myMethod").marshal(elToCSV).to("file:" + outFolder + "?fileName=test.csv");
it sets automatically a 0 and not an empty field into my output.
is there any parameters to define that i've missed ?
thanks
A field with the type int can not be set to null. This is just not possible in Java. Use Integer instead for nbRoom.

Can I address a repeated property or a structured property using a ndb.key

I tried to address a repeated property element using a key, like : ndb.Key('Books', 'Programming.one') but this key (the .one part) is not valid.
My example model below is a simplified version of my app's model. In this example code I have dependencies (using keys) between book chapters and tags :
class Tags(ndb.Model):
tag = ndb.StringProperty()
example : Tags(id = 'python', tag = 'python')
class Books(ndb.Model):
book = ndb.StringProperty)
chapters = ndb.StringProperty(repeated = True)
example : Books(id = 'Programming', book = 'Programming', chapters = ['one', 'two'])
class Dependencies(ndb.Model):
chapter_key = ndb.KeyProperty()
tag_keys = ndb.KeyProperty(repeated = True)
example :
chapter_key = ndb.Key('Books','Programming.one')
dependency_key = ndb.Key('Dependencies', chapter_key.id())
Dependencies(key = dependency_key, chapter_key = chapter_key,
tag_keys = [ndb.Key('Tags', 'python'), ndb.Key('Tags', 'java')])
Is it possible to address a repeated property using a ndb.Key. In my code example the chapter_key is not valid. Can I use a hook or property subclass to make it work?
To make it work I can combine a valid Book Key with a StringProperty to hold the chapter.
book_key = ndb.Key('Books','Programming')
chapter = 'one'
dependency_key = ndb.Key('Dependencies', book_key.id() + '.' + chapter)
Dependencies(key = dependency_key, book_key = book_key, chapter = chapter,
tag_keys = [ndb.Key('Tags', 'python'), ndb.Key('Tags', 'java')])
But I would like to benifit from a key.
I have the same question for a structured property. For this question the repeated StringProperty chapters is replaced by a repeated StructuredProperty like :
class Chapters(ndb.Model):
chapter = ndb.StringProperty()
word_count = ndb.IntegerProperty()
About my example and the use of keys :
I use keys in Dependencies, because keys in dependencies can refer to different kinds. These kinds differ from the Book like kind, because they do not have a repeated property like Book chapters. I use repeated depends_on_keys in my application, instead of chapter_keys.
In the example I also left out the parent keys. The Book like kind can have dependencies, but in my application you cannot find entities, which depend on the Book like kind.
No, you cannot use a key to identify a part of an entity. If you want to reference a part of an entity, you will need to use a key in conjunction with your own scheme for addressing entity parameters.
I am curious because the code above dont seem right in sintax terms:
tag_keys = [ndb.Key('Tags', 'python', ndb.Key('Tags', 'java']
You can use the code bellow, it worked for me:
class SomeModel(ndb.Model):
pass
class WithKeys(ndb.Model):
keys=ndb.KeyProperty(SomeModel,repeated=True)
keys=[ndb.Key(SomeModel,i) for i in range(1,10)]
with_keys=WithKeys(keys=keys)
print with_keys.keys
It prints:
[Key('SomeModel', 1), Key('SomeModel', 2), Key('SomeModel', 3), Key('SomeModel', 4), Key('SomeModel', 5), Key('SomeModel', 6), Key('SomeModel', 7), Key('SomeModel', 8), Key('SomeModel', 9)]
Goog luck

How to Extract Apache Camel URI parameters

Does anyone know how to extract parameter from camel URI?
I have a route defined like this
from("SOME_URI")
.to("SOME_URI")
.to("bean:myBean?method=myMethod&myParameter1=val1&myParameter2=val2")
I want to extract parameter1 and parameter2 in "myMethod" like this (I'm implementing camel in Grails)
def myMethod(def inBody, Exchange exchange){
String parameter1 = extractParameter('myParameter1')
String parameter2 = extractParameter('myParameter2')
...//rest of code
return something
}
Thank's in advance!
Main Answer
You can get what you're looking for out of the exchange:
exchange.getFromEndpoint()
Will return the Endpoint defined by "SOME_URI" and:
exchange.getFromEndpoint().getEndpointUri()
will return the String value of "SOME_URI"
Meaning your code could become:
def myMethod(def inBody, Exchange exchange){
def uri = exchange?.fromEndpoint?.endpointUri
if(uri) {
String parameter1 = extractParameter(uri, 'myParameter1')
String parameter2 = extractParameter(uri, 'myParameter2')
//...rest of code
}
return something
}
/*
* do any kind of processing you want here to manipulate the string
* and return the parameter. This code should work just fine in grails
*/
def extractParameter(String uri, String parameterName) {
def m = uri =~ "${parameterName}=([^&]+)"
return m.find() ? m[0][1] : null
}
If a Java equivalent is preferred, this should do the same:
private static String extractParameter(String uri, String parameterName) {
Matcher m = Pattern.compile(parameterName + "=([^&]+)").matcher(uri);
return m.find() ? m.group(1) : null
}
Alternative
Also note that, depending on what exactly you're trying to accomplish, a better approach might be to use the fromF DSL to supply parameters directly to your route. That way, you have the parameters available in code and you don't have to worry about extracting them, afterward.
The code snippet below is taken from the Camel Documentation of FromF.
fromF("file://%s?include=%s", path, pattern).toF("mock:%s", result);
Are val1 and val2 hardcoded values, or should they be some kind of dynamic value, maybe from the message itself?
The Camel bean component allows you to define the binding, and pass in values from the message or fixed values. See more details at: http://camel.apache.org/bean-binding.html
And you would also need to look at the number of parameters in your method signature, and the number of parameters you define in the Camel bean binding uri. They should match up.
If I understand correctly, you are trying to pass parameters into a method that is going to be invoked. The usual way to do this is to modify the Exchange object as it's flowing through the route.
from("SOME_URI")
.to("SOME_URI")
.setHeader("myParameter1", constant("val1"))
.setHeader("myParameter2", constant("val2"))
.to("bean:myBean?method=myMethod")
In your method, you just access the headers of the Exchange.
def myMethod(Exchange exchange) {
String parameter1 = exchange.getHeader("myParameter1", String.class)
String parameter2 = exchange.getHeader("myParameter2", String.class)
//...rest of code
}
Or if you want to get fancy and use Camel's bean binding,
def myMethod(Exchange exchange,
#Header("myParameter1") String parameter1,
#Header("myParameter2") String parameter2) {
//...rest of code
}
Please remember to vote up if this helps.

Resources