How to set "web application properties" so HSQLDB can use them? - java

I want to use HSQLdb for my Spring-based web application, and I want to have the data persistent (so in-memory is out). According to the hsqldb documentation, I can use variables in the connection URL - but the document doesn't say how to set these.
I've read this question, and there are some interesting tactics, such as creating a listener to set properties when the context loads.
This question explains how to get an appropriate location, so I've combined the two approaches. I've tried using a listener to set a new property with the path lifted from javax.servlet.context.tempdir (it's a File), I've tried using that property directly. Neither approach works.
One punter has commented that one could set user.home via a listener, then use ~ in the HSQLdb URL. I've not tried this, but even if it does work, it strikes me as a little yuck, as I redefine something I potentially don't want to. I'm looking for the "proper" way. How do I set that which the HSQLdb calls "web application properties"? (Or is there one that would be suitable?)
From the documentation:
If the database URL contains a string in the form of ${propname}
then the sequence of characters is replaced with the system property
with the given name. For example you can use this in the URL of a
database that is used in a web application and define the system
property, "propname" in the web application properties. In the example
below, the string ${mydbpath} is replaced with the value of the
property, mydbpath

From reading the source code, System.setProperty(key, value)
Kicking myself - my issue was first an ancient version of HSQLdb then it wasn't unloading - a restart of Tomcat, and everything started working.

Related

Is there an alternative to setting the 'derby.system.home' system property?

So I'm using derby for a patient management learning project. I'm using the following code to set the system property for derby's database write location..
Path path = Paths.get(System.getProperty("user.home"), "patient_management_databases");
System.getProperties().setProperty("derby.system.home", path.toString());
log.info(String.format("Set derby home to '%s'.", path.toString()));
My question is whether this is good practice on an application that is meant to be distributed and used in production? Changing the derby home location could cause problems in other applications using derby (I'm assuming all derby applications will access this property). Is there a way to set the path for this application only? It was saving to my project folder before which isn't ideal because of IDE indexing and having to ignore them when using VCS.
I was able to get the behaviour I wanted with the following code:
private final Path databaseDirectory = Paths.get(System.getProperty("user.home"), "patient_management_databases");
String.format("jdbc:derby:%s/%s;create=true", databaseDirectory.toString(), databaseName);
Using System.getProperty("user.home") is a nice way of abstracting the file-dependent nature of system paths. The use of Java's Paths abstraction is also another step in the right direction to decouple the application from the underlying file system. So the steps you have take so far are good, and may be sufficient for your use case.
However, there are multiple ways you can make the derby.system.home variable available to your application, and they all vary in terms of pragmatism and simplicity. I could not possibly describe all of them, but I would suggest also trying out a configuration file that you can load using different mechanisms - from the file system, from the classpath, or even from a remote server etc.

Purpose of storing variables in web.xml?

A lot of the advice on the web on storing variables which may change depending on the env/other conditions is to put them in web.xml, but isn't the web.xml within the war file? even if you find the exploded war and change it, wouldn't it get overriden if you update the war file? Or does the webcontainer provide any method to configure the web.xml without tinkering with the war file?
The web.xml variables are of very limited use, in my experience - the only advantage is that it's a standard location to look for hard-coded "configuration".
There are several common solutions to get a more sensible way to configure web apps, none of which is standard:
Use system properties (which usually involves fiddling around with startup scripts, and it can be hard to get a good overview of your entire config)
Use environment variables (same drawbacks as system properties)
Read a config file from a predefined location; often from the classpath by using getResourceAsStream (IIRC that usually means putting the config files in Tomcat's lib directory)
You can also use JNDI, which has the disadvantage of being rather heavy-weight both to set up and read (if you're using vanilla Java, anyways - Spring for example has rather good support for reading from JNDI). However, JNDI is rather good because it's per-application, and not a process-global setting. If you need to run several instances of the same app on the same server, JNDI is pretty much the only option (although you can use it to just point out a config file somewhere, which makes things easier to work with).
This may be relevant to your interests: How can I store Java EE configuration parameters outside of an EAR or WAR?
Advantages of specifying Parameter Values in web.xml
Using your own settings file requires additional coding and management.
Hard-coding parameter values directly into your application code makes them more difficult to change in the future, and more difficult to use different settings for different deployments (eg: JDBC settings, mail server address).
Other developers using your code will be able to find any relevant parameters more easily, as this is a standard location for such parameters to be set.
See also:
Advantages of specifying Parameter Values in web.xml
Web.xml.EnvEntry
Referencing Environment Variables in web.xml
As far as I know web.xml does not provide ability to store custom variables. Typical way to configure your web application is to store configuration in database, separate properties/xml/json/other file, get configuration from separate web service or provide it through environment variables.
Often a mixture of all these is used. For example you can add system variable using -D switch when running your container. This variable will contain path to file or URL where your configuration can be found.
You can supply parameters using OS environment.
You choice should depend on how many parameters do you have, what kind of application are you developing and how can you configure application server or computer OS. For example if you a hosting application on server you cannot configure these ways are not for you, so DB or web service are your only ways.
The folks that work on the Tomcat container recognize the irony that you have identified and have implemented a way to work-around the issue.
The solution that they implemented for the issues that you have alluded to is to create another xml file... the context.xml file, which is read by the server.
It appears that you can edit this file and have the new values read by the Tomcat without a restart... as long as you keep the elements out of the server.xml.
I do not use Tomcat so I might be mis-interpreting the docs
The GlassFish web container supports a similar feature, but does it via a couple admin cli command (asadmin):
set-web-env-entry
set-web-context-param
There is probably web admin console support and you can set them up by editing the domain.xml. It seems like it isn't as flexible as the Tomcat implementation... but it does make it really easy to use.
You need to disable and then enable your application for the changed values to 'take'. Do not redeploy you app, since that will delete the value that you just set.

Editing server.properties programmatically causes no change?

I am trying to implement a simple database configuration editor (to change host, port, user, etc.), but after saving the /WEB-INF/classes/server.properties file, changes do not seem to be recognized (the old configuration is still there when I access the built-in database configuration page). How can I tell SmartGWT to reload the database configuration?
Usually Application reads properties at sturtup and sets theese properties to java objects. So if you are changing properties during your application lifetime you need to take care about rereading them after your change and recreating (refreshing) objects that use them.
For more specific example please provide some code.
You can use the Config class to do this. Simply call the following static method to reload the global config.
Config.initGlobalConfig();
See http://www.smartclient.com/smartgwtee-latest/server/javadoc/com/isomorphic/base/Config.html for more information.

Centralized Application properties for multiple system

I am looking for a open-source solutions which allow hosting different properties for different applications and allow changes. On any change of properties it should notify or push the change to the application appropriately.
So, instead every application managing the properties in physical file and deploying physically; these properties can be pushed to a single system. User will have GUI to load and change the properties as per right. Should allow push as mentioned.
If you have already similar open source solutions in mind please advice.
Is this something that Puppet can manage for you?
I don't think what you've described (as nice as it would be) will be likely to exist in an app server. If a program is looking for a file, it's either going to load it with a FileReader (or similar), or it will use ClassLoader.getResourceAsStream(). It might be looking for data that is returned in properties, format, XML properties format, or even something completely different like RDF with which to configure itself. Also many programs read their config on start-up and then hold the values in memory, so you would still need to reboot them to get them to change.
To get something like this to work there would need to be a standard for configuration provisioning and live updates. Once that existed the webapp authors and server vendors would each need to add support for the standard.
If you are the one writing the programs to be managed however, then you can write your programs to request configuration from a service, and have a configuration push feature.... there may be packages out there that can speed up adding that to your code, but I get the impression you are looking to manage programs written by others.
Have you considered to use JMX? I think he could be a good starting point to implement your requirements.
MBeans's attributes can store your application's properties, the MBeanServer will allow you to make them available from remotting, JConsole offers you an GUI to update properties values.
You also can write within the MBean some code that notify the corrrespondig application when a user change any properties using the GUI.

Where should a Java web application store its data?

My Java web application (myapp.war) ist deployed by placing it into the webapps direcotry on Tomcat on Ubuntu 10.04.
This application needs to save some data in files. But the user, which is running Tomcat (tomcat6) has no write access to the home directory /usr/share/tomcat6/ and no write access to the current working direcotry /var/lib/tomcat6/, since both belong to root.
So where should a web application store its data? I hope it is not the extracted archive in the webapps direcotry. This one could be deleted very easily by accident. And Tomcat can be configured, not to extract .war files. Then there would be no extracted direcotry.
Perhaps /var/lib/tomcat6/ should belong to user tomcat6 ant this is a bug in Ubuntu?
If the files need not persist longer than the life-cycle of the servlet context, the servlet container provides a private temporary directory for each servlet context, specified by javax.servlet.context.tempdir attribute.
See Servlet Specification 2.3, Chapter 3 Servlet Context
3.7.1 Temporary Working
Directories
The convenience of a temporary
storage directory is required for each
servlet context. Servlet containers
must provide a private temporary
directory per servlet context and
make it available via the
javax.servlet.context.tempdircontext
attribute. The object associated with
the attribute must be of
type java.io.File
Answering his own question, Witek stated /var/lib/tomcat6/webapps/ is writable -- at least on his installation of his version of Ubuntu. On my RHEL 5.2 system /var/lib/tomcat<X> doesn't even exist, so there is no webapps subdirectory writable or not, which leads to my answer.
Q: Where should a Java web application store its data?
A: Wherever you've configured it to store its data.
Make the location configurable, in web.xml as a <context-param> or in a myApplication.properties file.
I can put it where I want on my box, the SysAdmins can put it where they want on the production system.
You can change your mind later.
You don't need symbolic links (which have magically disappeared on me before, breaking the system.)
You can have several sets of test data, and just point the configuration at whichever one you want.
You can put it wherever there's disk space.
You are going to change your mind later.
I think it depends on what kind of data you are dealing with. Most of the time, data goes into the database simply because it is fast and easy to perform a CRUD. If you want to store localized user configuration and you don't care how portable it is, perhaps you can store under user.home, I did that for one of my projects and that works fine. All that being said, I really don't think there's any best practice on this and database seems to be the most obvious choice because you can do whole lot of different tasks against it, and most of them are free to begin with. :)
I found the solution on Launchpad. /var/lib/tomcat6/webapps/ is writable. This means, that the following works:
File myFile = new File("webapps/myfile.txt");
I haven't seen any specific guidance on where you should store that kind of data locally - probably because you'd normally store that kind of data in a database.
When I need to store quick-and-dirty data like that, I store it on a filesystem specifically for that data, to isolate it from other areas where it might get caught up in other activity. Haven't had any issues with the approach so far. Also, if it's important, make sure you store it somewhere where you're backing it up :)

Categories

Resources