I am trying to set dynamic path in camel file component to avoid platform specific paths. But camel is not allowing this as it doesn't expect $ in directory path.
What I am trying to do is to set a VM param say file.home and then use this into my file component like
file:\${file.home}\type1
This will allow me to eliminate the platform specific path directly.
I tried externalizing this into property file but then Spring doesn't understand the camel specific dynamic language for e.g. ${in.header.abc}
Can someone help me out in achieving this.
Those answers are not correct. If you use a BridgePropertyPlaceholderConfigurer and a PropertiesComponent, you can use dynamic values everywhere.
<bean id="bridgePropertyPlaceholder" class="org.apache.camel.spring.spi.BridgePropertyPlaceholderConfigurer">
<property name="properties">
<value>
...normal property syntax name=value - use this in test definitions
</value>
</property>
</bean>
Or use something like this in real application
<bean id="dummyPropertyPlaceholder" class="org.apache.camel.spring.spi.BridgePropertyPlaceholderConfigurer">
<property name="location" value="classpath:/dummy.properties" />
</bean>
e.g.
<route id="DummyRoute">
<from uri="file:{{dummy.int.dir}}?delay={{poll.delay}}&initialDelay={{initial.delay}}&{{readlockChanged}}&move={{root}}/{{dummy.arch.dir}}/{{archive.dir}}&moveFailed={{error.dir}}&scheduledExecutorService=#scheduledExecutorService" />
<to uri="file:{{root}}/{{dummy.int.destination.dir}}" />
</route>
There is a trick with later versions of Camel: use $simple{file.path} instead of ${file.path} so Spring won't strip your ${} and pass the bare file.path to Camel. E.g. a move on an input 'from' uri might be like this:
move=archive/$simple{date:now:yyyyMMdd}/$simple{file:name}
http://camel.apache.org/how-do-i-use-spring-property-placeholder-with-camel-xml.html
http://camel.apache.org/using-propertyplaceholder.html
You can use dynamic uri but only in to endpoints (using specific components). You can't use it as from.
There you can find explanation how to use toD (from Camel 2.16) or recipientList: How to use dynamic URI in to
But as I said - there is only possibility to use it in to. It's not possible to use it in from. As a workaround, you have to write a route for each location you are expecting to be in use. You can also use autoCreate=false option to not creating other directories automatically, because for example Linux path without autoCreate=false option: /home/user/test will create directory structure in Windows c:\home\user\test
Since Camel 2.16
We can use
.from("file://folder")
.toD("file://folder/${file:onlyname}")
Here are some details about using properties within camel and/or spring xml: http://camel.apache.org/using-propertyplaceholder.html
According to Camel File Component:
Camel supports only endpoints configured with a starting directory. So
the directoryName must be a directory. If you want to consume a single
file only, you can use the fileName option e.g., by setting
fileName=thefilename. Also, the starting directory must not contain
dynamic expressions with ${} placeholders. Again use the fileName
option to specify the dynamic part of the filename.
So, you could do somethings like:
from(...).to("file://?fileName=${somePathAndSomeFile}").to(...)
Some of the comments/answers in this thread are misleading, as it's possible to set the value of "from" endpoint URI to have a value of a directory taken from a properties file as asked.
Place propertyPlaceholder element under camelContext, and ensure that the properties file could be found in the classpath
<propertyPlaceholder location="dir.properties" />
<from id="_fromInputFolder" uri="file:{{fromDir}}?"/>
Related
I wonder if there is a way to extract properties from Spring Environment (e.g. obtained from ApplicationContext) in the form of Properties instance? Or, at least, is there a way to enumerate the properties in Spring Environment, or get them all as a map, or any other way I can turn a [initially unknown] set of properties into a Properties object?
I need this in order to create a jclouds Context by calling org.jclouds.ContextBuilder.newBuilder() and .overrides(Properties). The idea is to configure the actual cloud provider solely by means of .properties file, and I don't want to couple application logic with provider-specific properties.
[UPDATE]
The .properties files to be used are configured using <context:property-placeholder>, and it actually specifies a list of paths, like this:
< context:property-placeholder location=
"classpath:/jdbc.properties,
file:${jboss.server.config.dir}/jdbc.properties,
file:${catalina.home}/conf/jdbc.properties"
ignore-resource-not-found="true"/>
which suggests that the .properties file is searched in the mentioned list of locations in order. I would like to achieve the following:
keep the list of .properties files and their possible locations in this XML definition file only;
allow to place jclouds related properties in any of the .properties files mentioned in the XML;
access the properties, resolved and loaded by Spring, in the form of Properties object so I am able to feed that to jclouds ContextBuilder.
Please let me know if all of this is feasible. Thank you in advance!
-Vlad
If you wan't to use properties in your Spring configuration then you can simply use:
<context:property-placeholder location="classpath:foo.properties" />
To get the properties in your code later you can simply read this file from the classpath into a Properties object:
props.load(MyClass.class.getClassLoader().getResourceAsStream("foo.properties"));
Alternatively you can have a look at PropertyPlaceholderConfigurer.
UPDATE
Updated after Deinum's remark but only if you are getting the properties from a Spring managed bean:
<util:properties id="myProps"
location="classpath:foo.properties"/>
<context:property-placeholder properties-ref="myProps" />
Now you can inject myProps into Spring managed beans (no need to load them again from the classpath).
You could use PropertiesFactoryBean and do something like this:
<bean id="jcloudsProps"
class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location">
<value>your/props/file.properties</value>
</property>
</bean>
You can then use jcloudsProps as you would any other Spring bean.
I've run into a strange obstacle using Apache Camel's file component. The gist of the problem is this: I'm using the file component to load in all messages from a directory. I then use a processor to perform some operation on the files loaded. If the process succeeds, then I move the file to a different location and delete the original file. If the process fails however, I leave the message in it's original directory. The code looks something like this:
from("fileLocation")
.process(new MessageProcessor())
.choice()
.when(header("processPassed").isEqualTo(true))
.to("file:newLocation")
.otherwise()
.to("fileLocation");
If the processor passes then everything works great. However, if the processor fails and I'm trying to return the message back to its original location, that doesn't work. Any idea on how to fix this?
I think there are two problems affecting you. Firstly you cannot write the file back to the original location because Camel is processing it and second there is a risk that you'll repeatedly process the same file. To get around this you can use two options:
preMove to use a working directory
idempotent to prevent the same file be processed a second time.
Here is a slightly modified version of your code that I believe does what you require
from("file:fileLocation?idempotent=true&preMove=working")
.process(new MessageProcessor())
.choice()
.when(header("processPassed").isEqualTo(true))
.to("file:newLocation")
.otherwise()
.to("file:fileLocation");
More details available in the File Endpoint documentation.
Read the documentation, there is a moveFailed option that you can specify.
It is a good thing to have the files placed in some error folder, and not the original location though. Then you will know where to look for bad files.
Update:
Since it's a firm requirement that you need to leave the files in place, you need to setup a persistent idempotent repository.
This is mostly copied from docs, and will save the absolute file paths of the processed files into a file on disk - so that it will never process the same (filename) again.
<!-- this is our file based idempotent store configured to use the .filestore.dat as file -->
<bean id="fileStore" class="org.apache.camel.processor.idempotent.FileIdempotentRepository">
<!-- the filename for the store -->
<property name="fileStore" value="some/folder/.idempotentrepo/filestore.dat"/>
<!-- the max filesize in bytes for the file.-->
<property name="maxFileStoreSize" value="<some size>"/>
</bean>
<camelContext xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="file://some/folder/?idempotentRepository=#fileStore&noop=true"/>
<to uri="mock:result"/>
</route>
</camelContext>
I am developing a Web application in Java using Eclipse and Tomcat 6.
I need to pass a value to the servlet that is not hard-coded into the .war file.
For instance, let's say my servlet needs a filename, and that filename is different on each server.
How do I pass it to the servlet, without hardcoding it in the .war file?
Please help me with the instructions on how to do this:
from within Eclipse (for instance: add xxxx to file yyy and then run)
on the server on which I will deploy the application
I'm thinking in the direction of getInitParameter, but I haven't found a way to pass init parameters except for the web.xml inside the .war file, which is not an option since it needs to be configurable. So if you could show me how I can set init parameters in an external file, the problem is solved.
Note: I'm looking for really exact advice, as in “edit that file on that location”. I have found many related questions and answers, but none of them was specific enough to make it work.
There are a number of ways to go about this. It really depends on at what point you know the location of the file you are trying to load. If it is something you will configure per tomcat instance/server then an environment variable or JVM argument would probably be easiest. You could then look up this variable via System.getProperty in your code.
You can pass a JVM argument on a per-tomcat basis via CATALINA_HOME/bin/setenv.sh.
#!/bin/sh
CATALINA_OPTS="$CATALINA_OPTS
-Dmy.file.path=/path/on/this/host/file.txt"
And in your code:
String path = System.getProperty("my.file.path")
Dhanush's suggestion is also a good one that might be more sustainable in the long run. It has the advantage of keeping all of your per environment configuration in a single location that you can keep in source control. With his approach however you'd still need a way to select the appropriate key from the properties file (because this properties file would be bundled in your war), which you could again use an environment variable or JVM argument to control.
If you wanted to get slightly fancier you could look into using JNDI
If the location of the config is known, you can pass it as a servlet parameter. In your web.xml where you declare your servlet (I refer to configFile as the file you wish to get a reference to):
<servlet>
<servlet-name>ConfigParser</servlet-name>
<servlet-class>foo.baar.ConfigParser</servlet-class>
<init-param>
<param-name>configFilePath</param-name>
<param-value>/path/to/the/config/file</param-value>
</init-param>
</servlet>
I guess you know where the web.xml file is because you are already using servlet.
Then in your servlet, you can you ServletConfig.getInitParameter("configFilePath") to get the location of the config file. e.g. in your servlet:
public void init(ServletConfig config) throws ServletException {
super.init(config);
String path_to_config_file=config.getInitParameter("configFilePath");
}
Container will call this method with the ServletConfig where you get your reference to the config file.
That means, you are not required to have that file in eclipse at all. With this approach, you don't have to do anything special on your server, the only thing to take care of is that the file is copied over and the path you declare on your web.xml is correct.
If the location of the file can be constructed dynamically, you can use ServletContext.getRealPath("/") that returns the absolute path of the webapp.
---UPDATE---
Answer to the updated question. I don't know what is the best practice to do it, but there is a workaround. You create a file (conf_location.txt) in the tomcat home directory which contains one line with the location of the file you want to pass to the servlet. In your servlet, you can get access to the file with this hack (given your war is in $TOMCAT_HOME/webapps/mywar.war):
public void init() throws ServletException{
String contextPath=getServletContext().getRealPath("/");
File tomcatHome=new File(contextPath).getParentFile().getParentFile();
File configFile=new File(tomcatHome,"conf_location.txt");
try {
String config_location = new Scanner(configFile).useDelimiter("\\Z").next();
} catch (Exception e) {}
}
For a real project, you shouldn't be using servlets directly. Use a framework that helps guide you in a direction. Spring is very common.
If you use Spring, in your application context you'll have a bean called a Property Placeholder Configurer. See for example: spring PropertyPlaceholderConfigurer and context:property-placeholder. The best practice is to hard code that file location (either file: or classpath:), but have that live outside the WAR file.
application-context.xml:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:config/properties/database.properties</value>
</list>
</property>
<property name="ignoreResourceNotFound" value="true"/>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
There are several design problems with loading configuration files in the code that needs it. It makes testing hard, it makes the general design less flexible, and if tomorrow you think that a property file is insufficient and you want to store configuration in something like ZooKeeper or JNDI, you have to rewrite a lot of code. Write your code as objects that get injected with settings instead, and instantiate them following the dataSource pattern from above.
In your servlet code you can load it from a Properties file, which is residing in your classpath, like this
Properties props = new Properties();
try {
props.load(this.getClass().getClassLoader().getResourceAsStream("config.properties"));
} catch (IOException e1) {
log.error(e1.getMessage(), e1);
}
String prop1 = props.getProperty("prop1");
I have created my own component and I want to do something similar to this:
<camel:camelContext id="camel1">
<camel:route>
<camel:from uri="mysch://realthing?network=${network}" id="testEndpoint"/>
I want ${network} to come from a properties file (using Spring properties placeholder):
<context:property-placeholder location="classpath:test.properties"/>
How can I do that?
See this FAQ
http://camel.apache.org/how-do-i-use-spring-property-placeholder-with-camel-xml.html
I'm wondering about Spring 3.0 whether it provides an automatically generated service definition page after I defined services.
With SOAP we have a WSDL file which contains WHAT, HOW and WHERE we can call a service.
Is that possible with Spring 3.0 or not?
Yes it does. Just add "?WSDL" to the URL of your Spring-generated web service and you'll get the definition. Also you can append "?xsd=1" instead and you'll get the schema you need (this is referenced also from the WSDL).
You can use an MBeanExporter to expose all of your services via JMX, which would be viewable through a JMX dashboard on your container (IE Tomcat, Jboss, etc). This is an easy way to account for 'what is deployed'. Your question is not entirely clear what sort of artifact you're looking for though.
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="autodetect" value="true"/>
</bean>
Will automatically export all of your defined beans as MBeans. Usually that's not entirely what you want, so alternatively, you'll specify them manually.
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="beans">
<map>
<entry key="bean:name=testBean1" value-ref="testBean"/>
</map>
</property>
</bean>
I agree with Chochos.
These[?wsdl, ?xsd=N] are universal standard to find the service definition file and any Datacontract defined in the wsdl.
example:
if http://localhost:8080/MyService is your service endpoint then it is service container's responsibility to make the WSDl available at http://localhost:8080/MyService,
by default.
The answer is Yes,
Use tag in your message dispatcher spring context file.
if your message dispatcher bean id is spring-ws then the spring context file for it would be spring-ws-servlet.xml.
In that context file,
import the namespace http://www.springframework.org/schema/web-services/web-services-2.0.xsd
xmlns:sws="http://www.springframework.org/schema/web-services".
then use the tag dynamic-wsdl from this namespace.
Also, you can set attributes for it like portType, binding and id. This will generate the wsdl file for you. You can view it by querying for it in the browser
/.wsdl