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.
Related
We have two JEE applications in our WebSphere 8.5.x environment that both depend on a common JAR. Without going into too much detail, suffice it to say that the JAR needs to be set up as a shared library and attached at the server level. I would like to know how to manage this shared library without having OS access to update the file, instead updating through the WAS console.
As I understand it, for a WAS shared library you need to have placed it somewhere on the OS before you can set up the shared library reference since you have to provide the path to the e.g. JAR file.
I would like to be able to complete a deployment, replacing all binaries including the shared library, without having to remote into the OS and update the JAR on disk. I would prefer a method where someone using the WAS console could update the shared library on disk much like they can upload a new application.
I've looked into a WAS "Asset" (WAS Console -> Applications -> Application Types -> Assets), with the hope that this would allow me to manage and upload the JAR file through the console. I am able to upload the JAR as an asset and can see it when it lands on disk, but I am not understanding what to expect from this and am loathe to use this without knowing everything that's going on.
I see the "Asset binaries destination URL" option but that doesn't seem to do anything. I can put anything I want in that field when importing the asset and it always goes to "${APP_SERVER_ROOT}/config/cells/${CELL_NAME}/assets/${ASSET_NAME}/aver/BASE/bin/" on the management node, not the worker node. This location is also the configuration repository, and I get a funny feeling mapping directly into a repository location like this.
I could, I suppose, create the shared library with a path directly into that location but I am concerned that I'm missing something and that this isn't a good idea.
Does anyone have any insight into this they could share?
To use a shared library with WebSphere you can go to Environment > Shared Libraries and upload/configure a shared library on that page (including choosing which applications you want to associate with the shared library).
For full info, see IBM's doc: Creating shared libraries
You could try to use Business level applications and upload jars as asset, specify them as shared libraries and map during application installation (however I've never done that and it might not work). Check the following links:
Business level applications
Creating business-level applications with the console
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.
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.
I need to create a Lucene index on a Java EE application startup, but I do not want to decide on the location of the index in filesystem myself. How do applications in general store any files created while running, is there any kind of store provided by the engine per application basis etc. that I can use.
I do not want to decide on the location of the index in filesystem myself. How do applications in general store any files created while running, is there any kind of store provided by the engine per application basis etc
By default the classes in the java.io package resolve relative pathnames against the current working directory - i.e. the location in the file system from where the java command was invoked - that you can get using the user.dir system property:
String curDir = System.getProperty("user.dir");
But doing this is far from ideal (actually, writing to files is not ideal for portable applications) and I don't recommend this approach but suggest using absolutes filesystem paths and e.g. system properties:
new File(System.getProperty("my.directory" + File.separator + "xxx");
Where the property my.directory would be set in the app server startup script e.g. assuming JBoss is installed under /opt, using -Dmy.directory=/var/opt/jboss/<somedir> to be FHS compliant.
Just keep in mind that:
Writing to the FS is not ideal for application portability. Prefer writing to a database if possible
Using java.io from EJBs is in theory forbidden.
Normally you create a Lucene index in application servers like JBoss and Tomcat in the current directory (.), index folder is created in bin folder, which is not a good idea at all.
You can either store your index files in database (or virtually any other storing device) using Compass or store it in a path on the file system.
There is no special per-application storage as far as I know in Java EE containers.
I would say that the best way is to store the data on a default path in the filesystem, for example /var/lib/your_application/ and then make that location be configurable.
You can read more here:
http://www.pathname.com/fhs/pub/fhs-2.3.html
Where do you store user-specific and machine-specific runtime configuration data for J2SE application?
(For example, C:\Users\USERNAME\AppData\Roaming</em> on Windows and /home/username on Unix)
How do you get these locations in the filesystem in platform-independent way?
First on the format:
Java property files are good for key/value pairs (also automatically handle the newline chars). A degree of structure is possible by using 'dot notation'. Drawback is that the structure does not allow you to easily enumerate top-level configuration entities and work in drill-down manner. Best used for a small set of often tweakable environment-specific settings
XML files - quite often used for more complex configuration of various Java frameworks (notably J2EE and Spring). I would advice that you at least learn about Spring - it contains many ideas worth knowing even if you decide not to use it. If you decide to roll your own XML configuration, I'd recommend using XStream with customized serialization options or if you just need to parse some XML, take a look at XOM. BTW Spring also allows you to plug your custom XML configuration language, but it's a relatively complex task. XML configuration is best used for more complex 'internal' configuration that is not seen or tweaked by the end user.
Serialized Java objects - a quick and easy way to persist the state of an object and restore it later. Useful if you write a configuration GUI and you don't care if the configuration is human readable. Beware of compatibility issues when you evolve classes.
Preferences - introduced in Java 1.4, allow you to store typed text, numbers, byte arrays and other primitives in platform-specific storage. On Windows, that is the registry (you can choose between /Software/JavaSoft/Prefs under HKLM or HKCU). Under Unix the same API creates files under the user home or /etc. Each prefs hive can be exported and imported as XML file. You can specify custom implementation of the PreferencesFactory interface by setting the "java.util.prefs.PreferencesFactory" JVM property to your implementation class name.
In general using the prefs API can be a good or a bad thing based on your app scenario.
If you plan to have multiple versions of the same code running on the same machine with different configuration, then using the Preferences API is a bad idea.
If you plan using the application in a restricted environment (Windows domain or tightly managed Unix box) you need to make sure that you have proper access to the necessary registry keys/directories. This has caught me by surprise more than once.
Beware from roaming profiles (replicated home dirs) they make up for some funny scenarios when more than one active machines are involved.
Preferences are not as obvious as a configuration file under the application's directory. most of the desktop support staff doesn't expect and doesn't like them.
Regarding the file layout of the prefs it again depends on your application. A generic suggestion is:
Package most of your XML files inside application's JAR either in the root or under /META-INF directory. These files will be read-only and are considered private for the application.
Put the user modifiable configuration under $APP_HOME/conf . It should consist mainly of properties files and occasionally a simple XML file (XStream serialization). These files are tweaked as part of the installation process and are usually not user serviceable.
Under the user-home, in a dot-directory (i.e. '~/.myapplication') store any user configuration. The user configuration may override the one in the application conf directory. Any changes made from within the application go here (see also next point).
You can also use an $APP_HOME/var directory to store any other mutable data which is specific to this application instance (as opposed to the user). Another advantage of this approach is that you can move and backup the whole application and it's configuration by simple copy of one directory.
This illustrates some standard techniques for managing configuration. You can implement them using different libraries and tools, starting from raw JRE, adding Spring/Guice or going for a full J2EE container (possibly with embedded Spring)
Other approaches for managing configuration are:
Using multiple base directories for running multiple instances of the application using different configurations.
Using lightweight registries for centralized configuration management
A centrally managed Configuration Management Database (CMDB) file, containing the host-specific values for each machine is rsync-ed every night to all production hosts. The application uses a templated configuration and selects from the CMDB during runtime based on the current hostname.
That depends on your kind of J2SE Application:
J2SE executable JAR file (very simple): use user.home System property to find home-dir. Then make a subdir accordingly (like e.g. PGP, SVN, ... do)
Java Web Start provides very nice included methods to safe properties. Always user-specific
Finally Eclipse RCP: There you have the notion of the workspace (also derived from user.home) for users and configuration (not totally sure how to access that tricky in Vista) for computer wide usage
All these approaches are, when used with care -- use correct separatorChar -- OS neutral.
Java has a library specifically for doing this in java.util.prefs.Preferences.
Preferences userPrefs = Preferences.getUserNodeForPackage(MyClass.class); // Gets user preferences node for MyClass
Preferences systemPrefs = Preferences.getSysteNodeForPackage(MyClass.class); // Gets system preferences node for MyClass
Preferences userPrefsRoot = Preferences.getUserRoot(); // Gets user preferences root node
Preferences systemPrefsRoot = Preferences.getSystemRoot(); // Gets system preferences root node
I use this
String pathFile = null;
if(OS.contains("win")){
pathFile = System.getenv("AppData");
}else{
pathFile = System.getProperty("user.home");
}
I save the settings of my application here
C:\Users\USERNAME\AppData\ on windows
user.home (/home/USERNAME) on other platfroms
For user specific config, you could write a config file to the folder pointed to by the "user.home" system property. Would only work on that machine of course.
You might want to look at Resource Bundles.