Camel Processor And .cfg File - apache-camel

Does anybody know if there is a chance to read a .cfg file directly in a camel processor?
My .cfg looks like:
key=value
key=value
...
And I want to get a specific value after its key, but I want to do that in a processor!
Thank you!

Just use plain old Java:
Reader reader = new FileReader("myprop.cfg");
Properties prop = new Properties();
prop.load(reader);
Also have a look at Read contents of a file containing key value pairs without normal parsing. As Claus Ibsen stated, there are good chances that a File -> Properties converter will be added in future Camel versions, see https://issues.apache.org/jira/browse/CAMEL-7312.
If you just need to access some key value pairs, use Camel's properties component:
<bean id="properties" class="org.apache.camel.component.properties.PropertiesComponent">
<property name="location" value="classpath:com/mycompany/myprop.cfg"/>
</bean>
Access the property in your routes with the {{key}} syntax:
<to uri="{{cool.end}}"/>
The Camel documentation shows all possibilities.

Related

How to use properties with the SimpleRegistry in Apache Camel (Spring XML)

I want to use a SimpleRegistry to store properties (as global variables). The property is changed with setProperty in a route with a jms endpoint. The camel documentation changed last week and has many dead links, also the Registry page. I did not found any samples that describe the use of the simpleRegistry.
I used the camel-example-servlet-tomcat as base. I do not use Fuse or the patched camel wildfly, because is to huge for our simple module.
<beans .... >
.
.
.
<bean id="simpleRegistry" class="org.apache.camel.support.SimpleRegistry" />
<camelContext xmlns="http://camel.apache.org/schema/spring">
<propertyPlaceholder id="properties" location="ref:simpleRegistry" />
<route id="storeConfig">
<from id="myTopic" uri="jms:topic:myTopic?selector=Configuration %3D 'xyz'" />
<log id="printHeader2" message="Received header: ${headers}" />
<log id="logToken" message="Received token: ${headers[myToken]}" />
<setProperty id="setMyToken" name="myProperty">
<simple>${headers[myToken]}</simple>
</setProperty>
</route>
<route id="externalIncomingDataRoute">
<from uri="servlet:hello" />
<transform>
<simple>The Token is: {{myProperty}}</simple>
</transform>
</route>
</camelContext>
</beans>
With the camel context deined like above, I got a java.io.FileNotFoundException Properties simpleRegistry not found in registry.
When I use <propertyPlaceholder id="properties" location="classpath:test.properties" /> and create a test.properties file, everything works fine but I cannot change the property. The operation in the setProperty tag is ignored.
The reason why I need a global variable is, I send a dynamic configuration (the myToken) via a jms topic to the camel context. A single route should store this configuration globaly. If an other route is called via an rest component, this route need the token to make a choice.
Alternatively you can achieve the same result following the below approach which uses the PropertiesComponent
<bean id="applicationProperties" class="java.util.Properties"/>
<bean id="properties" class="org.apache.camel.component.properties.PropertiesComponent">
<property name="location" value="classpath:application.properties"/>
<property name="overrideProperties" ref="applicationProperties" />
</bean>
Define the property place holder in the camel context:
<propertyPlaceholder id="propertiesRef" location="ref:applicationProperties" />
Set a property as shown below :
<bean ref="applicationProperties" method="setProperty(token, 'Test'})" />
And to fetch the property : ${properties:token}
OK, there are multiple subjects in your question.
You write you want to use Camel SimpleRegistry, but you obviously have a Spring application.
If you got Spring available, the Camel Registry automatically uses the Spring bean registry. The Camel Registry is just a thin wrapper or provider interface that uses whenever possible an available registry of another framework.
The Camel SimpleRegistry is only used when nothing else is available. This is basically an in-memory registry based on a Map.
You want to set an application property with <setProperty>.
<setProperty> sets an Exchange property, NOT an application property. With this you can save values in the Exchange of a message.
You want to use "global variables".
You could perhaps use a Spring singleton bean that is a Map. You could then autowire it where you need it, it would be like an application wide available map.
However, think twice why you need this kind of variable. This could also be a symptom of a design problem.

Is it possible to get file name while reading a file using WSO2 ESB File Connector 2

I am doing a simple file read using WSO2 ESB File connection 2. I try to read a .OUT file from the given directory. It reads the first file (alphabetical order?) well but I have no idea which file is read. Is there a (transport?) property that gets populated when a file is read?
Here is my code in a proxy service
<fileconnector.read>
<source>file:///D:/temp</source>
<filePattern>.*\.OUT</filePattern>
<contentType>text/plain</contentType>
</fileconnector.read>
<log level="full"/>
I get the following response
INFO - LogMediator To: /services/SampleProxy.SampleProxyHttpSoap12Endpoint, WSAction: urn:mediate, SOAPAction: urn:mediate, MessageID: urn:uuid:f5737693-6a51-4044-9134-95cd61eaeaa4, Direction: request, Envelope: <?xml version='1.0' encoding='utf-8'?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><text xmlns="http://ws.apache.org/commons/ns/payload">abc,123
qwe,456
</text></soapenv:Body></soapenv:Envelope>
Give it a try like this. (Just a suggestion. I didn't try.)
<log level="custom">
<property name="FileName" expression="$trp:FILE_NAME" />
</log>
If you want to read a particular file, you can pass the full path as a value in source and you can skip the file pattern value.
<fileconnector.read>
<source>file:///D:/temp/abc.OUT</source>
<filePattern></filePattern>
<contentType>text/plain</contentType>
</fileconnector.read>
This is a valid requirement. We will consider this in our future release. Please use [1] to track the progress.
[1] https://wso2.org/jira/browse/ESBCONNECT-192

Camel reverse proxy - no response stream caching

I am trying to implement a memory efficient http reverse proxy that is only working on streams. The Jetty consumer places the input stream into the exchange and I can hook it up with a http producer to forward the request. No problem there.
However, all http producers that I am aware of (Jetty, http4, netty-http) read the response stream into heap memory and place its contents into the exchange in some form or another instead of a handle to the stream. And none of them seem to offer an option to make them do so.
I found this thread which describes the same problem and also suggests a solution. But looking at the code of the http4 HttpProducer in Camel 2.13.1, it does not look like the proposed change made it into the Camel code base after all.
Is there any way to achieve the stream-only approach with Camel? So, with a minimal memory footprint I could do something along the line of this:
<route id="reverse_proxy" streamCache="false">
<from ref="jetty.http.server"/>
<bean ref="streamHolder" method="enableCaching"/>
<bean ref="streamHolder" method="parsePayloadHeaderInfoAndDoStuff"/>
<bean ref="streamHolder" method="resetStream"/>
<to ref="http.client"/> <!-- Register completion synchronization hook to close stream. -->
<bean ref="streamHolder" method="enableCaching"/>
<bean ref="streamHolder" method="parsePayloadResponseHeaderAndDoStuff"/>
<bean ref="streamHolder" method="resetStream"/>
</route>
EDIT - Additional info on where exactly the input stream ends up in memory:
http4: Everything happens in org.apache.camel.component.http4.HttpProducer::process() -> populateResponse(..) -> extractResponseBody(..) -> doExtractResponseBodyAsStream(); and here the original stream is copied into an instance of CachedOutputStream.
Jetty: org.eclipse.jetty.client.AsyncHttpConnection::handle() -> org.eclipse.jetty.http.HttpParser::parseNext() will fill a byte array in org.eclipse.jetty.client.ContentExchange which is a CachedExchange which is a HttpExchange.
netty-http: Builds a pipeline that assembles the HttpResponse content as a composite ChannelBuffer. The wrapped channel buffers make up the complete response stream.
I have debugged all three clients and did not stumble across a branch not taken that would leave me with the original input stream as the exchange body.
This is reproducible with a route as simple as this:
<camelContext id="pep-poc">
<endpoint id="jetty.http.server" uri="jetty:http://{{http.host.server}}:{{http.port.server}}/my/frontend?disableStreamCache=true"/>
<endpoint id="http.client" uri="jetty:http://{{http.host.client}}:{{http.port.client}}/large_response.html?bridgeEndpoint=true&throwExceptionOnFailure=false&disableStreamCache=true"/>
<route id="reverse_proxy" startupOrder="10" streamCache="false">
<from ref="jetty.http.server"/>
<to ref="http.client"/>
</route>
</camelContext>
I have an Apache2 return a 750MB file as large_response.html.
EDIT 2
Indeed this is a problem with all available HTTP producers. See this thread on the Camel mailing list and the corresponding JIRA ticket.
They do not read the stream into memory unless you access the message body on demand, and tell Camel to read it into memory as a String type etc.
See this cookbook example how to do a stream based proxy
http://camel.apache.org/how-to-use-camel-as-a-http-proxy-between-a-client-and-server.html

Fuse ESB/OSGI/Blueprint reading configuration files alphabetically?

I experience something rather strange and I would like to know if other people have experienced the same...
I am currently working on a project using jboss fuse (previously fuse esb) and we are using blueprint for our configuration files.
We use property place holders and have the following files under src/main/resources/OSGI-INF/blueprint:
blueprint.xml
properties.xml
In blueprint.xml we have something like this:
<bean id="myBean" class="com.test.MyClass">
<property name="prop1" value="${my.prop}" />
<∕bean>
Then in properties.xml I have this:
<cm:property-placeholder persistent-id="my.properties" update-strategy="reload">
<cm:default-properties>
<cm:property name="my.prop" value="true" />
</cm:default-properties>
</cm:property-placeholder>
And I obviously have a setter for prop1 (which is a String) in MyClass.
But what I see is that when I deploy this, prop1 is set to "${my.prop}" instead of "true", i.e the variable never gets replaced with its defined value!
But now if I call the properties file aaa_properties.xml, it works!!
Is this a bug in the blueprint container?
Did any one else experience the same behaviour?
Thanks for your feedback :)
JM.
I found some information about Blueprint Configuration in Fuse ESB
It states:
If you need to place your blueprint configuration files in a non-standard location (that is, somewhere other than OSGI-INF/blueprint/*.xml), you can specify a comma-separated list of alternative locations in the Bundle-Blueprint header in the manifest
For Example:
Bundle-Blueprint: lib/account.xml, security.bp, cnf/*.xml
I suggest, can you please give this a try, and specify your xml files here, naturally in the correct ordering.

iBatis - Why is sqlMapConfig.xml unable to find the sql maps defined in it?

I have a sqlMapConfig.xml that has three SQLMaps defined in it.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMapConfig
PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
<!-- Statement namespaces are required for Ibator -->
<settings enhancementEnabled="true" useStatementNamespaces="true"/>
<!-- Setup the transaction manager and data source that are
appropriate for your environment
-->
<transactionManager type="JDBC">
<dataSource type="SIMPLE" >
<property name="JDBC.Driver"
value="com.mysql.jdbc.Driver"/>
<property name="JDBC.ConnectionURL"
value="jdbc:mysql://localhost:3306/sug"/>
<property name="JDBC.Username"
value="root"/>
<property name="JDBC.Password"
value="admin"/>
</dataSource>
</transactionManager>
<!-- SQL Map XML files should be listed here -->
<sqlMap resource="com/tatakelabs/dbmaps/categories_SqlMap.xml" />
<sqlMap resource="com/tatakelabs/dbmaps/pro_SqlMap.xml" />
<sqlMap resource="com/tatakelabs/dbmaps/pro_category_SqlMap.xml" />
</sqlMapConfig>
I get a runtime error - Cause: java.io.IOException: Could not find resource com/tatakelabs/dbmaps/categories_SqlMap.xml
categories_SqlMap.xml is present in that location. I tried changing the location of the map xml, but that did not help. sqlMapConfig.xml validates against the DTD. categories_SqlMap.xml also validates against the right DTD. I am at my wits end trying to figure out why it can't find the resource. The sqlMap files are generated by iBator.
This was happening because the sqlmap file location was not getting copied to target. Added a copy goal and that fixed it.
I had the same problem. It appears the problem lies with the location of the config file. Thus, its in relation of the project resource structure.
I moved the config file in the same package as the mapper classes and it worked. In this case try moving all the resources to this package and update the resource attributes to:
<sqlMap resource="categories_SqlMap.xml" />
<sqlMap resource="pro_SqlMap.xml" />
<sqlMap resource="pro_category_SqlMap.xml" />
Solved it.
I moved the xml file to where the Pojo was located and provided the path as follows:
<sqlMap resource="com/heena/ibatis/model/jsr/jsr.xml" />
And it worked.
place it ...src\java\abc.xml under the Source Packages directory.
If you are using Spring, you can use a SqlMapClientFactoryBean specifying property "mappingLocations". In this property you can specify a generic path, such as "com/tatakelabs/dbmaps/*_SqlMap.xml" or with a variable such as ${mapfiles}, that will be resolved by Spring as an array of file names. This lets you omit sqlMap element in sqlMapConfig. This technique will run with iBatis 2.3.4 on. However sql-map-config-2.dtd is also contained inside iBatis.jar, so you can experience some parsing errors, as /com/ibatis/sqlmap/engine/builder/xml/sql-map-config-2.dtd may have a bug. In this case you may want to replace it inside the jar with the one from the URL:
http://ibatis.apache.org/dtd/sql-map-config-2.dtd.

Resources