Where to place a writable properties file in a java webapp? - java

I'm using a properties file to store configuration information for a webapp. I'd like to allow the user to set certain values via the webapp. I'm just wondering where I should place it?

I see this is tagged with Spring. Have you looked at the PropertyPlaceHolderConfigurer ?
This can be used to specify multiple property files used to expand properties in the Spring configs. You can use this to (say) specify a properties file on the classpath (in your app bundle) and an optional overriding properties file in (say) the user's home dir.
That way you can provide defaults in the app, and override using optional properties files in the user's home directory, the /etc/ filesystem etc. This is what I typically do, providing locations for different prperties files that are user-editable (in /home) and admin editable (in /etc).
I appreciate that this doesn't quite answer your question, but gives you new options for what you really want to achieve.

If it is project setting conf file, I would put it to ${user.home}/app/app-conf.properties
platform independent & uniform and easily accessible place

Related

Add a file to spring properties

I would like to add a file to a spring properties YAML file. What would be the best way to do it?
I'm providing default files, but the user has to be able to change them and add his files as well. These files are mainly certificates and keystores.
My solution to this problem is to encode a file in base64 and then store this string as a property to load at the runtime. But i wonder if there is a better way to store these files?
For example:
trustedProfileKeystoreFile: MIIJcgIBA(..)zCCCTwGCSqGS
But i need a way to store multiple files also:
trustedCertificateFiles:
- Q2VydGl(..)maWNhdG
- RQTF4zr4(..)fzaw512
However Spring does not allow to store a list of strings like in the example above and i would have to "hack" it like in the post in patrickjamesbarry comment.
I cannot store all files in a single folder and then load this folder because the application will be available at docker and that would mean that i have to mount multiple folders for multiple types of files, and that's not acceptable. I need to have a centralized way to save all files.
yml file is the configuration file, and you cannot overload it with something which has no relation to it.
you should rather put the file locations in YAML file, and extract data in code.

Java - how to make a library I made use config values

Long story short, I'm making a java library that requires several 'config values'. Currently, I'm just using a config.properties file in the root directory and reading from it, but I don't see how that can work with a distributable jar file.
I've thought about making these config values parameters to a constructor of a class in the library, but there are too many values- it just doesn't seem like the correct way of doing things.
Essentially, I just need some way that a user of my library can just use the jar file, but also have the ability to change several configuration values that affect the function of the library.
If it makes any difference, I'm using maven to build my project.
Thanks in advance.
(Assuming you are just working in JavaSE, as Java EE has other configuration mechanisms.)
A pattern is to create a singleton class in your jar that provides configuration to the other classes. Which is reads default values from the property file in the jar. Allow the caller of the jar to override properties by setting them as system properties.
In the java doc for Property class there is a constructor to provide defaults and overrides and get the 'net' properties.
Giving the caller the option specify a property file by giving a file path as a system property.
Log4j and java.util.logging work of like this. Reading through there config documentation will help explain.
I will split your question into two parts and then answer each part separately.
I've thought about making these config values parameters to a constructor of a class in the library, but there are too many values- it just doesn't seem like the correct way of doing things.
For the part of your question I have quoted above, see the accepted answer (written by me) to the following StackOverflow question: How to handle large number of configuration parameters across a program conceptually?
Essentially, I just need some way that a user of my library can just use the jar file, but also have the ability to change several configuration values that affect the function of the library.
It sounds like your configuration file will contain N variables, and a user might want to customize the values of, say, just 2 or 3 of those variables. If N is relatively small, then it will probably be okay to use an either-or approach to configuration:
either the user provides a configuration file containing values for all N variables (the location of this file might be specified via, say, a system property, an environment variable, or a parameter to the constructor of your library);
or your library uses a "built-in" set of default configuration values, which I suggest you place in a properties file that you bundle into your library's jar file and then access by calling ClassLoader.getSystemResourceAsStream().
However, if N is large, then you might want your library to provide and semantics for configuration variables:
your library uses a "built-in" set of default configuration values, which I suggest you place in a properties file that you bundle into your library's jar file and then access by calling ClassLoader.getSystemResourceAsStream(). This provides default values for all N variables.
and your library loads an (optional) user-specified configuration file that might contain anywhere between 0 and N variables. The values of the user-specified configuration variables are used to override the built-in default values.
Obviously, you will need to implement the and logic within your library, but that is really just a SMOP (Simple Matter of Programming). Perhaps the simplest way is to iterate over the entries in the user-provided Properties object and copy them into the Properties object that contains the default values. In this way, the user-specified value will override default values.

A "Resource bundle" for persisting other then localization data

I need system similar to ResourceBundles except that I will not use it for localization. Basically, I need to store several versions of settings. One version of that settings is String-to-String map, that can be represented by Properties file. These settings versions must be easily persisted to file system inside application .jar (alike PropertyResourceBundle).
The idea is to have different versions of application settings (settings profiles), represented by key-value pairs of type string, that can be chosen from at application start up based of user decision. Again these are not language versions so ResourceBundle (according to its javadoc) is not the right way to implement it.
Any easy way how to do that without implementing the whole think myself? Please do not suggest third-party it should only use Java SE classes.
Edit: I forgot to mention one important detail. It would be hard for me to get stream like this: Thread.currentThread().getContextClassLoader().getResourceAsStream("/your/resource/here");. That is because the project that would contain properties file is compiled by Ant and used as a dynamically loaded library in different GUI projects that actually run. I might have all properties files in fixed project folder but since Thread.currentThread().getContextClassLoader() returns context of GUI project and I do not know where in that project was the .jar with property file placed by Ant I do not know what to use as "/your/resource/here".
I might have misunderstood the question however seems to me you can easily do something like this:
InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("/your/resource/here");
Properties prop = new Properties();
prop.load(inputStream);
This will be safe in a Java EE environment as well and you can call you anytime you need if you want settings to change.
Update: as long as the resource is on the classpath you should be able to find it without knowing the full path of the resource as well.

Internationalization - listing and adding languages

I'm making an application in Java. This application can be internationalized using ResourceBundles. I want to allow user to choose the language that he want to the application have. And there's a question: how to list available languages for the program? I don't want to use Locale.getAvailableLocales(), because I don't know if the app's got a .properties file for the chosen language. There's also the second question: can I add an ability to add additional language files outside the .jar file? And the last question: is there any better internationalization solution?
Regards
You could just store a fixed list of supported locales in some constant of your application. If you need to make this dynamic, I see two solutions:
use a properties file listing the supported locales, and load them from this properties file at startup.
iterate through the available locales (or languages), try to load a corresponding bundle properties file (using Class.getResourceAsStream()), and consider that the locale is supported if you get an InputStream, and not supported if you get null.
You could let the user add a bundle by putting some directory in the classpath, in addition to your jar. Drop the properties file in this directory (respecting the package hierarchy), et voilĂ .

Where/how to store persistent data with tomcat?

Where should I store persistent files in a Tomcat web app ?
javax.servlet.context.tempdir is not feasible, it's erased when the app is redeployed/removed
Don't want to use an absolute path in e.g. servlet init parameters
Storing the files in a database is not an option
Our team does this a lot. A general rule we follow is outside the web app and outside Tomcat.
Our sysadmin set up a directory on our server that the tomcat user has rw permissions to (e.g. /var/tomcat/persist). We have a built a directory structure under this that tomcat uses to store files, read app-specific init files, etc.
If you don't want to use an absolute path in your init-params for your servlet, consider setting a system property when tomcat is started up. The good thing about that is every application running under tomcat will have access to it. The bad thing about that is every application running under tomcat will have access to it. You could set a property named base.persist.dir and build subdirectories for each application underneath it. We set system properties in the setenv.sh script in the bin/ directory under the CATALINA_OPTS environment variable.
Answering the title of the question, what about using a database, a DataSource and JDNI? Even in a web only context, writing to files using java.io is not really recommended because of concurrency, threading, security, clustering, portability issues. Some of these problems can be "workarounded" but still, this is not really a best practice. The standard approach is to use a database and I'd suggest to reconsider this option, throwing "file-based" lightweight database like HSQLBD or JavaDB into the mix.
(EDIT: For an unknown reason, database is not an option. Using JNDI or context parameters or init parameters to pass an absolute path - which are the less worse options IMHO - is excluded too. For a relative path, maybe look at user.home or user.dir then - or any other system property that you could pass on the command line. I don't like it, I wouldn't do it, and this doesn't solve the issues previously mentioned, but it's your choice after all.)
Storing the files in a webapp directory under the home directory of the user running Tomcat is a good and convenient option. It is outside of Tomcat, which means it will survive redeployment, and it is usually a writable directory (because it is created under the users' home dir).
But it is always a good idea to allow overriding the location of such directory via system property.
Generally, this would go to the database. But since the OP insists on not using a database, I'd try a different approach:
Filesystem path which is known: ${user.home}/.myapp. Applications sometimes use this for e.g. search indices which can be recalculated based on data in the database. Might be okay for your use case to use the user's home.
Store the configurable filesystem path in a configuration repository such as the database or perhaps Java Preferences (if you don't like to use servlet init params). Commercial applications such as Atlassian JIRA use a configurable (but absolute) filesystem path where they store issue attachments. If they don't know a better way, i don't know who does :)
I generally would suggest to use a database to store persistent data and expose it via a DataSource.
If you don't want to do that, I guess you could consider using the "user.home" system property (I have seen this used in a few circumstances). But... there are no guarantees that your servlet will be run with permission to write access unless you configure that yourself.

Categories