I need to have hibernate database config set from outside text file, how can I do it? Is there some kind of method for this, or do I have to make my own?
You can programaticaly configure hibernate within your app: http://docs.jboss.org/hibernate/core/3.3/reference/en/html/session-configuration.html#configuration-programmatic
HTH
Hibernate configuration file (*.cfg.xml) have to be in the class path of your application's war.
But, you can maintain file like 'install.properties' in deployment folder of your application.
Inside it you can maintain database related properties.For eg.
database.name =
database.hostname=
database.username=
databse.password=
Use some predefined constant string inside 'hibernate.cfg.xml' that you can replace during time of application deployment task. For eg.
<property name="hibernate.connection.url">jdbc:mysql://$database.hostname/$database.name</property>
you can write an 'ant' task which 'unwar' the war then replace constant strings with values as mentioned inside 'install.properties' and then make 'war' again.
In this way you can separate out configuration settings from application code structure.
Hibernate configuration files have to be on the class path but can be outside your war. The exact way to add a directory or files to the class path will depend on your app server so you'll have to mention which one you're using (for Tomcat, see this previous question for example).
Related
We have a database library that gets the connection information (user, host, etc) from a properties file. This file can be a config.properties file located in the classpath, or next to the execution jar or can be passed as an argument -Dproperties=/path/to/myConfig.properties.
We also have several applications that use this library, so each one has its own config.properties file used in its own execution.
But now I'm creating two web applications that use the same library. So, if I deploy them in Tomcat (war file), I have two options (to my knowledge):
1.- Include each config inside the WAR file. But with this, every time I need to tweak something in the config.properties I'll have to repack the war.
2.- Pass the -Dproperties parameter as an execution argument of Tomcat. But different war deployments will have to share the same properties file.
Is there a way around this?
Can I pass the -D argument to a specific deployment in Tomcat (or any other server)?
PS: This is one of the scenarios we have, but is not constraint to database connection info. We have other libraries that get parameters through config.properties file.
EDIT: I want to be able to have different config.properties file for each deployment. Not the same properties shared among them.
I think I found a way around using self contained webserver inside the application, like Jetty.
We've a similar requirement in which we share a common property file between different applications deployed into JBoss EAP server.
In $JBOSS_HOME/bin/standalone.conf file you can add configuration file path as below:
JAVA_OPTS="$JAVA_OPTS -DCONFIG_LOCATION=/external/config/configuration.properties"
Start the server with above specified property and within your application you can read this property file with apache commons-configuration api as below:
try {
props = new PropertiesConfiguration(System.getProperty("CONFIG_LOCATION"));
FileChangedReloadingStrategy strategy = new FileChangedReloadingStrategy();
// Delay 30s
// strategy.setRefreshDelay(30000);
props.setReloadingStrategy(strategy);
} catch (ConfigurationException e) {
e.printStackTrace();
}
With this reload strategy you can change your properties while your server is running. Also you can specify the interval after which all properties specified in the external file needs to be refreshed within your application without bouncing it. Hope this helps!
You can create an environment variable whose value will be the path where the properties file are located. Later use this environment variable will creating bean for property placeholder config.
for UNIX, you can add in your bash profile file
export CONF_DIR=/path/to/conf
And in spring context file, add this
<context:property-placeholder
location="file:///${CONF_DIR}/path/myConfig1.properties,
file:///${CONF_DIR}/path/myConfig2.properties"
properties-ref="applicationDefaultProperties" ignore-resource-not-found="false"
ignore-unresolvable="false"/>
So, when you want to change any thing in the properties file, you can change at one location, and then restart the application to load the new values in your app.
So, if your config file is this
db.user=username
db.password=password
Inside java class, you can use the keys as like this
#Value("${db.user")
private String username;
#Value("${db.password")
private String password;
The solution I found for my problem is using an embedded web server in my application. In my case, I'm using Jetty.
Now I pack my application as an executable jar and pass the system parameters as -D arguments and they live inside the instance of the application.
Like this:
java -Dproperties=config.properties -jar java_app_with_embedded_server.jar
Where can i store SLF4J configuration file so that all production and test environment may have access to it? I want to store the config file outside of the web app at an arbitrary location and retrieve that location upon startup. I also want to allow for changing location of the config file so no classpath. Im thinking about using getters and setters to retrieve the file path.
Any ideas??
slf4j is (for all practical purposes) just the API. You need a backend which does the actual work.
If you use logback you can ship a logback.xml file with your application which just includes another file. If I recall correctly the filename string can hold a ${variable} which you can then define outside your application.
See https://logback.qos.ch/manual/configuration.html#configFileProperty
You may specify the location of the default configuration file with a system property named "logback.configurationFile". The value of this property can be a URL, a resource on the class path or a path to a file external to the application.
java -Dlogback.configurationFile=/path/to/config.xml chapters.configuration.MyApp1
I use Neatbeans to create a Java Class Library Project. This class (name: TestDB.java) is to do some DataBase jobs. I wrote a "config.properties" file to config some properties. The config.properties is located in the Project folder. In my class TestDB.java:
Properties properties = new Properties(System.getProperties());
String configFile = "config.properties";
properties.load(new FileInputStream(configFile));
String param1 = properties.getProperty("Postgre.Driver1");
I can use a test case to get the property, That's OK.
When I build this project and create a jar file. I want another web application to use this jar file to do some DB jobs. I already include the jar in my webapp and bulid a webproj.war. When I place this webproj.war to Tomcat and run the webapp. I can't get the property because I don't know which folder in the Tomcat webapp to place the config.properties. Anyone can help me to solve this question ?
Sorry for the long answer, but I'm trying to cover the background as I think your question is a little bit confused.
This answer tries to clarify your understanding of web-apps and reusability a little more generally.
First, it's important to understand that applications typically have to run in multiple environments - dev, sit, uat, production, etc. If you include environment specifics in your binary (jar or war) that means you can only use that binary in a single environment.
The original J2EE assumption was that these environment specifics would be managed by the container (Tomcat in this case). This is what the answer referenced in the first comment of your question is doing. Basically the container provides resources registered in JNDI, which your application can look up.
Now, I think it's fair to say, the J2EE folks where wide of the mark with some of the features, the JNDI resource mechanism being one instance of this, which isn't commonly used these days (at least not in the applications I'm used to).
Now, to try and answer your question.
The first important thing to recognise is that the reason for putting code into a seperate jar is to make it reusable. Since Spring burst onto the scene, one of the fundimental ways to achieve reusability is with dependency injection. Spring aside, dependency injection is nothing more complicated that passing the resources a particular object needs at the time you create that object.
For example, your TestDB class might be instantiated as follows:
TestDB testDB = new TestDB(dataSource);
This still doesn't solve the problem of instantiating the DataSource, however it does place this responsiblity with the code using TestDB rather than TestDB itself.
The simple way to instantiate the DataSource would be include a properties file in the war's classpath (in WEB-INF/classes), which would allow you to do the following (note the DataSource instantiation will be database specific):
Properties properties = new Properties();
properties.load(getClass().getClassLoader().getResourceAsStream("config.properties"))
DataSource dataSource = new PGSimpleDataSource();
dataSource.setServerName(properties.get("database.server.name"));
...
So this gets you to the point where you're loading a properties file from within your war. However as I stated, this makes the war environment specific.
The best way I know to solve this is to use an exploded war with a symlink to the environment configuration. To do this, you use a context file which you would place in [Tomcat root]/conf/Catalina/localhost.
For example, the given context file:
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/my-app" docBase="/local/apps/my-app/war" distributable="false" allowLinking="true">
<WatchedResource>WEB-INF/web.xml</WatchedResource>
</Context>
You would have a directory structure like this:
local
+ apps
+ my-app
+ war
+ WEB-INF
+ classes
+ env -> /local/apps/my-app/env
+ env
Where /local/apps/my-app/war/WEB-INF/classes/env is a symlink to /local/apps/my-app/env.
Your properties would now be loaded like this:
Properties properties = new Properties();
properties.load(getClass().getClassLoader().getResourceAsStream("env/config.properties"))
This gives you two releaseable components - the application and the configuration that are simply unpacked to install them.
I have two spring projects both using maven. The first is a client for some api and the second is a console program that, in part, utilises that client.
I have packaged up the client into a jar and referenced it in the pom for the console program.
I have managed to get this working, just about, but I am not very happy with the solution:
1) The first problem I ran into was that each of the context xml files were named "applicationContext.xml". Therefore, I couldn't work out any way to reference the context file in the client, without renaming it to something else e.g. clientContext.xml. This works but is there any other way to reference it explicitly?
2) The next issue was how to invoke the clientContext.xml from within the console program. To do this, I have added <import resource="osrdClientContext.xml"/> to the applicationContext.xml of the console program and this seems to allow it to correctly find all of the defined beans. I'm not sure if this is best practice though?
3) Within clientContext.xml, I need to reference a properties file and so have the line <context:property-placeholder location="classpath:api.properties" />. This works when running the client on its own but appears to get ignored (or fails to find the file) when running the console program. The api.properties file is in the root of the packaged jar for the client and the jar is in the classpath of the console program. The only workaround I have found is to manually copy the properties file into the console program, at which point it is found without any problem.
4) Both projects have a resources directory with sub-directories "dev", "beta" and "prod". This allows me to define different properties depending on the maven profile I want to run against. This works fine for the individual projects but when I package the client, it only includes the properties files for the profile I am running against (which makes sense). However, that then means if I run the console project against profile "beta", it will still run the client against whatever profile it was packaged against. It would be handy to be able to package all of the properties files and get the client to run in the same profile as whatever is depending on it. Is that possible/a good idea?
Ad 1: The common place to put your JAR-based XML contexts is inside META-INF/your/project/name folder. You can check for example spring-batch-admin project. Also nowdays it is more common to name the context files {name}-context.xml (e.g. central-context.xml).
By following the advice above, you should not have problems with name conflicts. However it should be possible to overcome such problem by using classpath* pseudo protocol in your import definition:
<import resource="classpath*:do/not/put/in/root/this-can-be-duplicate.xml"/>
Ad 2: This is completely legit. You can see the same practice in the Spring Batch Admin example as linked above. Just add the classpath: or classpath*: to the resource path.
Ad 3: That is very strange and I have no clue to what is going on there.
Ad 4: This is possible to achieve via Spring profiles (not Maven profiles):
<beans profile="dev">
<context:property-placeholder location="classpath:META-INF/dev/my.properties"/>
</beans>
or via new SpEL support:
<context:property-placeholder location="classpath:META-INF/#{systemProperties['my.jvm.property']}/my.properties"/>
However what I like is to have a default properties and then let the main application be able to override them. This means, that your configuration will be on a single place and not inside the JAR. You can achieve this via properties hierarchy:
<context:property-placeholder location="classpath:META-INF/my-default.properties,classpath*:META-INF/my-optional-overrides.properties"/>
UPDATE just discovered that <context:property-placeholder> has problems with SPeL. However you can still use SPeL (and even other property configurers) when defining the PropertyPlaceholderConfigurer manually (i.e. via <bean>).
I would like to display the currently running version of my web application in the page. The project is based on Maven, Spring, and Wicket.
I'd like to somehow get the value of maven's ${project.version} and use it in my spring XML files, similarly to the way I use the Spring PropertyPlaceholderConfigurer to read a property file for settings that I use in my application.
If I had the maven project.version available as a variable in my Spring config, I could do something like this:
<bean id="applicationBean" class="com.mysite.web.WicketApplication">
<property name="version"><value>${project.version}</value></property>
</bean>
How can I do this?
You can use Maven filtering as already suggested.
Or you could just read the pom.properties file created by Maven under META-INF directory directly with Spring:
<util:properties id="pom"
location="classpath:META-INF/groupId/artifactId/pom.properties" />
and use the bean.
The only drawback of the later approach is that the pom.properties is created at package phase time (and won't be there during, say, test).
One technique would be to use mavens filtering. You can insert placeholders in resource files like which then get replaced with values from the build during the resource phase.
Look up "How do I filter resource files?" in the Maven getting started guide
Use the #PropertySource annotation to add the pom.properties file created by Maven in the META-INF directory. Note that the file doesn't exist until the package phase. To avoid errors during testing set the ignoreResourceNotFound=true and add a default value on the property being read (e.g. none below).
#Service
#PropertySource(value = "classpath:META-INF/maven/io.pivotal.poc.tzolov/hawq-rest-server/pom.properties", ignoreResourceNotFound=true)
public class MyClass {
private String applicationPomVersion;
#Autowired
public MyClass(#Value("${version:none}") String applicationVersion ) {
this.applicationPomVersion = applicationVersion;
}
public String getApplicationPomVersion() {
return this.applicationPomVersion;
}
}
We deploy property files outside of the web app. The files can then be filtered at deployment time.
If using Jetty one can put the file under $JETTY_HOME/resources or use the extraClassPath feature to load the property file at runtime.
I think the right way of gather application version is the one explained in this thread: https://stackoverflow.com/a/2713013/840635 through getClass().getPackage().getImplementationVersion().