Changing Spring PropertyPlaceholderConfigurer to read from another source - java

I'd like to extend/replace the Spring PropertyPlaceholderConfigurer to read from a web server as opposed to properties files.
A bit of background:
I work on a project, and we're finding the number of properties files located on the users systems is getting a little unwieldy. We'd like to replace these files with a 'config server' which will store basic key/value pairs and serve them when the user starts up the app.
To avoid making too many changes, I'd like to change the way the PropertyPlaceholderConfigurer finds properties - rather than implementing an entirely new way to manage properties. So on startup - Spring will read all properties from a url, and feed these into my spring config xml in the same way as it would have with actual files.
Bonus!
If anyone has any ideas how to do this where properties are reloaded from the server only when they change, will get bonus points (I have no idea if I have the ability to assign bonus points, but I'll try!). That would be a 'nice to have, if there's not too much effort involved' solution.

Spring's PropertyPlaceholderConfigurer (PPC) already uses the Resource interface to specfiy the location from where to read properties (via the setLocation(Resource) method inherited from PropertiesLoaderSupport.
There is an implementing class of this interface called URLResource which probably does what you want. You could simply create a PPC and set the location property with a bean of this type to load the properties from a URL instead of a file. This class also supports file:// type URLs, so you could switch between on- and offline properties loading depending on the URL you use.

Related

MyBatis Spring DYNAMIC number of multiple databases Java configuration

This is fairly straight forward with a simple Spring DAO approach. However, using MyBatis, is there a way to setup multiple potential datasources?
The best approach I can think of is to use an ArraList of a Bean each containing datasource.driverclass,datasource.url, datasource.username, datasource.password etc.
The values for the datasources are stored in individual properties files. There could be 1 or 10 of these property files (or more).
So for example, one application startup all the property files would be loaded one at a time into an ArrayList. Then, based on the NAME=value line from the property file, we would know which datasource to hit.
So http:localhost:8080/name=db1
... would access all the data from the datasource configured with the name "09". Each property file would contain:
name=db1
datasource.driverclass=jdbc:sqlserver
datasource.url=jdbc:sqlserver://localhost:1433;databaseName=someDBname
datasource.username=user1
datasource.password=pass1
So the identifier here is "name=db1".
Would the best approach from a MyBatis implementation utilise an ArrayList of Beans?
Here are some leads if you want to keep up with multiple DB:
Anyway, I would say datasources shall be managed in the server confiquration instead of in the App.
Then Mybatis main configuration file must be placed in a location added to the classpath, but outside of the app package, because every new datasource must be referenced there inside an environment element.
And for every user request or session (in case of a web app), the configuration will be parsed because SqlSessionFactoryBuilder.build(reader, environment=NAME); must be called to choose the environment (=> the DB).
I ended up using a hierarchical application.yml file detailing the multitenant connection values, based on a selected tenant code.

Spring load a file

I need to load a file from within a directory in the root of a WAR using Spring
This is the directory structure
rootOfWar
--static-dir
---- my-file.css
--WEB-INF
---- classes
.....
It is a normal WAR.
In a Spring #RestController I need to be able to read and write to my-file.css file. What is the best way to get the File, ServletContextResource or?
More Details
- The location of the file is out of my control I cannot move the file.
- The jee container is Tomcat.
- The Spring version is current 4.1.6
- The Spring environment is not using XML only annotations with WebApplicationInitializer, WebMvcConfigurerAdapter and an annotation configuration class.
Is there another way to do this like specify a file as a resource in the configuration so that it is loaded by the frame work and accessible within the application?
Basically I have JEE knowledge but my Spring knowledge on best practices concerning read/write are lacking.
If you need to modify a file you should not make it part of the WAR. Store it somewhere outside the web package and reference it there. Everything else will lead to problems, especially when you deploy to Websphere which is often run in a restricted environment where writes are rejected.
But I consider overwriting files in the web path bad design, because you are likely to run into caching issues. Better write a servlet that generates the CSS you need. If you would be able to name the content that should overwrite your css file, you are also able to render this dynamically.
Something like this may be already sufficient:
#RequestMapping(value = "/my.css", produces = "text/css;charset=UTF-8")
public String showCss() {
return "<here goes your css>";
}
(This is written from my memory and not tested).
The good thing is that you can modify the css any time you want and even set caching information as needed.

How to load app-wide settings at startup (for Spring3 webapp)?

I am in the basic stages of writing a Spring3 MVC webapp with Hibernate. I want all of data model classes to be able to access basic configuration values for example, database table prefix name, etc. I want this option, so I (or other developers) can change things on the fly by modifying them in the .properties file.
Is my best bet to create a Config class in a util package with a static block that loads a bunch of properties from a .properties file? I suppose the class itself could be static with a variety of getters to access the values within.
If I choose the method above, how could I insure the application didn't load (Failed gently) if for some reason the .properties file I have specified was not able to be loaded? With exceptions?
If my way stinks, what might be a better scenario?
Thanks!
That's a fine approach IMHO. If you would explicitly declare a bean for this class, like
<bean id="myConfig" class="com.yourcompany.yourproject.Config"/>
spring will fail at startup if it cannot instantiate the bean. So if the properties file is unreadable/not available just throw an unchecked Exception from Configs constructor.
if -for some reason- you enabled lazy loading globally you have to explicitly disable it for this bean, otherwise you won't get a failfast solution
<bean id="myConfig" class="com.yourcompany.yourproject.Config" lazy-init="false"/>
EDIT:
another nice feature of this scenario is that you can tell maven to 'filter' the resource (the .properties file), and you can get all the maven variables. This is how my prop file looks (I use this info for the About dialog. Does anybody ever opens an about-dialog btw?)
project.version=${project.version}
project.name=${project.name}
project.organization.name=${project.organization.name}
project.url=${project.url}
project.description=${project.description}

Overwrite configuration for Spring project from outside

I'm developing a Spring application which shall be used by any kind of other application, no matter if that is a Spring project, a web application or even a simple single-class console application. The application who uses my project will just have to add the JAR file with my application.
So my project has a static factory class that gets and returns a bean from its Spring context which acts as an access object to access all public available functions of my project.
That part is already working.
But I need the developer of the application that uses my JAR to be able to overwrite certain configurations in my project without editing the config files in the JAR itself. At the moment those settings should be overwritable:
- the data source and hibernate bean configuration
- the jasypt (encryption) bean configuration
- the log4j settings
How do I make those settings overwriteable with configs from outside the jar?
Greetings
touchdown
Maybe a good solution would be a configuration that the user could override, for this take a look into:
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-java
Specially to #Configuration and #Bean
Maybe you could have a configuration class implemented and the user can override it. After extending the class and overwrite some methods that provides some beans the user shall inform it to your factory that will do nothing else than
new AnnotationConfigApplicationContext(userConfigurationClass);
If you want to replace the complete configuration, than the easyest way would be to have a parametrized factory that takes an alternative configuration file as its argument.
If you need it a bit more fine grain (lets say up to 10 parts), than you can split your application xml in several smaller once, and use again a configurable factory that allows to exchange the smaller xml files.
So I got a solution that is working for me.
I put an general import for override context-XMLs at the bottom of my main application context:
<import resource="classpath*:project/package/config/override/or-*.xml" />
So all the user has to do is to create the package "project/package/config/override" in his classpath (e.g. resource folder) and place matching XML files in it with new bean definitions.

Where to put application-wide settings in Java (Servlet)?

In ASP.NET, there is web.config which can hold application-wide settings. Is there a corresponding file (residing outside of the war or jar archive) for a Java EE Servlet?
What I need is some place to point out a configuration file, which currently holds four attributes which in turn, taken together, leads to the database where the rest of the data and configuration is stored. (Server, database, username and password.) These values need to be easy to change without repackaging and redeploying the entire application, hence the configuration file, but hardcoding the path to the configuration file in the application (even if it is as a constant) seems far from optimal.
Any hints? I've tried Google but found very little that seemed relevant - and what I did find appeared hideously over-engineered for my needs.
In ASP.NET, there is web.config which can hold application-wide settings. Is there a corresponding file (residing outside of the war or jar archive) for a Java EE Servlet?
That's the web.xml. You can define settings as <context-param> entries.
<context-param>
<param-name>foo</param-name>
<param-value>bar</param-value>
</context-param>
It's available by ServletContext#getInitParameter(). The ServletContext is in turn available anywhere.
String foo = getServletContext().getInitParameter("foo"); // Contains "bar"
You can also access it by EL.
#{initParam.foo} <!-- prints "bar" -->
What I need is some place to point out a configuration file, which currently holds four attributes which in turn, taken together, leads to the database where the rest of the data and configuration is stored. (Server, database, username and password.) These values need to be easy to change without repackaging and redeploying the entire application, hence the configuration file, but hardcoding the path to the configuration file in the application (even if it is as a constant) seems far from optimal.
As per the emphasis, I'd use a properties file for this particular purpose which is then placed in a path outside the WAR. You just need to add this path to the Java runtime classpath. Then you can obtain it as classpath resource:
Properties properties = new Properties();
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("filename.properties"));
// ...
However, with the particular sole purpose to serve a DB connection, you're indeed better off with a servletcontainer-managed datasource as answered by Qwerky. All you possibly would need to configure is then just the datasource name.
If this is a web app then you'd be better served configuring the database connection as a resource on the server, then getting your app to retrieve it using JNDI. Your app server will have documentation on how to do this, its a basic task.
99% of serious web apps do this, the other 1% should.
You can have your application load an arbitrary external file by simply passing the path as a command-line parameter (to the servlet container startup script). Then store the values in the ServletContext

Categories