Question: I'm looking for a way to configure Java to create new files with a particular permission set by default.
Problem: I have a Spring Boot app which uses the following:
Log4J2 for logging
H2 for flat file databases
Ehcache for cached entities
All of these libraries create new files on the local file system, and when they do, they produce world-writeable files (666 for files and 777 for directories). I have seen this on macOS 10.13 (user has "umask 0022") and on Amazon Linux (user has "umask 0002").
If I was directly managing the creation of the files, I can do what I need with PosixFilePermission, but since file creation is delegated to the libraries, I don't have that opportunity. I could potentially set a timer to discover new files and set the permissions directly, but I'm not wild about that approach.
Log4J2 v2.9 added a filePermissions field to RollingFileAppender, so I have hope for one of my problems, but I'm not able to find something similar for H2 or Ehcache. Ideally, I'd like to do this at the JVM/Boot level for simplicity and future-proofing.
Here's a topic of tomcat and umask. Seems tomcat has it's own behavior dealing with umask.
So maybe there is a way to config the 'umask behavior' of tomcat embedded in Spring Boot? Like properties or something.
I cannot pretending this is an Answer. But sadly I don't have enough reputation to comment your question. Hopes this would help you a little.
Turns out this is a red herring. The issue is not with java, it's with the YAJSW service wrapper that launches the java process. YAJSW has several parameters for setting umask, including on the child process, but they are not implemented yet. Launching the app outside of YAJSW produces files that obey the user's umask.
Related
I was reading the 12 factor app manifesto http://12factor.net/. The manifesto recommends storing the configuration data for the application in Enviornment variables. Does this mean that properties like the DB username / password, resource URL should be stored as a part of Java Env variables rather than as property files ? Is this a secure way of storing the information ? To me this seems to be a pretty clunky way of storing the information.
Are there any best practices / experiences around this that can be shared ?
One option that I can think of is to have a separate configuration service running in the landscape, and use Env property to connect to the config service and then query the config service for further detailed configuration data.
12 factor apps are designed to run on platforms that orchestrate isolated UNIX processes. UNIX processes are configured via environment variables. While property files are a well-established Java convention, UNIX processes are a language-agnostic way to configure processes.
To support multiple configuration methods, a good best practice is to:
Read from process environment with System.getenv('CONFIG'), if null
Read from property file with properties.getProperty('CONFIG'), if null
Fall back to a default value
For more details, see Heroku's instructions on defining config vars for Java apps.
We can use Spring Centralized Configuration to do that, using centralized configuration we can commit configuration of all of our projects into a single repository and later on while writing build scripts we can override our local configuration from that repository to use that centralised configuration.
By clicking on below link you will find getting started guide to do so
https://spring.io/guides/gs/centralized-configuration/
This piece on How To Implement 12 Factor Configuration In Java maybe helpful: https://blog.codacy.com/12-factor-config-for-java/
It's published by Codacy, the automated code review tool.
Our system is split up into different environments, each one as a separate Tomcat instance.
Development (Windows)
QA: Accessed by our QA department (Linux)
Production: Live site, accessible to customers. (Linux)
Each of these environments rely on separate databases, and several other web services. This means we need to keep track of the various URLs, usernames, and passwords that are all different. Many of these settings are shared across several apps, so it would be ideal to have them all in one place to remove duplication.
Right now we have config files in the application itself. We use Maven profiles to fill in the different config settings when we build the app. But this is clumsy because we have to build a different WAR for each environment.
Where is a good place to store the config files so that we can deploy the same WAR file to each server?
I've done a fair amount of research on this already. But I haven't found an solution that completely makes sense to me yet.
Separate Config Directory
Define a directory to hold config files. Such as /opt/config on linux.
I like this idea, but how do I tell Tomcat where this directory is? I see references to context.xml, but every example I've seen puts the context.xml in the META-INF folder inside the WAR. Is there a way to configure this outside the WAR?
System Property to define environment
This involves setting a system property, and then using some sort of if/else or switching logic to load the appropriate config file. This seems workable, but a bit messy. But where/how do you set this property? I typically start tomcat with ./startup.sh. Do I add arguments to that command or is there another configuration somewhere?
JNDI
I don't think this is an option for us. Every tutorial I've looked at for this seems to be dependent on LDAP or something similar. To my knowledge we don't have that available to us, and it seems like too much overhead to get set up for only a half-dozen config files.
Use system property that refers to the location where your configuration file or directory is located. In this case you can manage different environment easily and no if/else logic is needed.
You application can have hard coded value of config file path, that will allow running application without any additional system property. The application however should fail to start if mandatory data is not found.
Concerning to partial sharing of data among environments.
You can split your data into several files by categories. Some files will be shared, some other different for different environments. You can even develop your own mechanism of references between data files.
However better approach is using some ready-to-use packages. For example Spring framework supports very flexible configuration mechanism. However if you already have Spring-less application introducing this framework for configuration only seems like an overkill. In this case take a look on Apache Commons Configuration package.
Worked with my team on this and we came up with what we feel is a cleaner approach. While every tutorial I found put the context.xml inside the WAR, it can also be placed in the conf folder of the Tomcat directory.
This works for us as all our servers are Tomcat based. So each server can have it's own context.xml which has a property pointing to the config folder on that particular server.
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 have a lot of configuration files that modify how my application behaves. I want to be able to make a change and it gets reflected in the application right away when saving the file. Is there a Java library to help with this?
I could simply keep a list of files with their timestamps and continuously check in a background thread when a timestamp changes. Doesn't seem too difficult, but maybe there's a more efficient way to do this? Custom triggers when certain properties have changed would be nice.
I'm using Spring 3.1, is there a built-in mechanism or solution which works nicely with Spring?
UPDATE: Apparently JDK7 now includes this functionality through its Watch Service API: "Most file system implementations have native support for file change notification. The Watch Service API takes advantage of this support where available. However, when a file system does not support this mechanism, the Watch Service will poll the file system, waiting for events." So this'll be my motivation to migrate to JDK7.
Edited:
http://commons.apache.org/configuration/userguide/howto_filebased.html
Within a Java EE environment (happens to be WAS 6.1 but could be any application server) I need to place a XML file, which is a configuration file, so that I can read and write to it.
This needs to be available in a clustered environment so I am looking at using the class path to load the file.
I am thinking I can store this file in the EAR root, reference it in the manifest and then load and save it.
I have tried this approach by having my file in a JAR and making this available via the MANIFES and I can load the config file from the class path no problem using the following.
this.getClass().getClassLoader().getResourceAsStream("configFileName");
That loads the file that is in the JAR, which is fantastic. But if I want to edit this file, programmatically, I cannot access the JAR files location (the EAR root) it returns me an interpreted path like this:
/usr/IBM/WebSphere/AppServer/profiles/AppSrv01/installedApps/localhostNode01Cell/MyApp.ear/MyApp.war/TB_config.jar
That is not the correct location of the JAR the correct location is at MyApp.ear.
So the question is: how can I access and update (copy contents, create new, save, delete old) the JAR with my config file.
Or should I put the config file somewhere else?
What is the standard Java EE to make files that need read/write access available to WARs on a cluster?
Ok I have built a solution for this. It is more WebSphere based (our platform) but it is J2EE and I am suprised it was not mentioned. Basically I have used JMX to synchronise the nodes. The files are stored, and saved to, the deployment manager the nodes are then resynchronised using JMX calls and then the engines withing the applicaitons are restarted by calling servlets within the applications.
It works a dream
So #stacker, nodes are managed and the manager distributes files to the nodes.
The problem that you've hit is not unique. A lot of Java EE programmers can struggle with providing a "configurable" property file to administrators of a cluster. And the solution that you've chosen, well, has its limitations.
The problem with embedding a config file inside a JAR, is absolute path or the physical path of the file, in case you need to update it. If your container will not explode your EAR and WAR files, then placing the config file alongside the code is a bad idea - the administrator will have to deploy a newer version of the EAR/WAR/JAR. That is unless, of course, you can configure the container to explode the artifacts - WebLogic Server does this, I'm not sure about WAS.
There are several ways to resolve this problem:
Store the config file in a SAN that is accessible to all the nodes in the cluster via a 'canonical' path. That way, you could locate the file from any node in the cluster and update it. Remind yourself to restrict access to this directory. Although this sounds simple, it need not be - Java objects might have to be 'flushed' across nodes, once the configuration file has been updated. Moreover, you might have to cater to the scenario where property files can get edited outside the application.
Use a database. Much simpler and almost hasslefree, except that the Java objects might have to be flushed again.
Use a MBean. As good as a database, except that I haven't known a lot of people vouching for the MBean support in WAS. Also, I'm not really sure if object states can go haywire across a cluster, in this case.
You cannot write to an ear file, you should place the XML file in the DB as a text lob (large object).
Actually, as I am using WebSphere, it appears I can use the dynamic cache provided by the WebSphere deployment manager. The last chapter in the link below dicusses the use of the Dynamic Cache providing a shared object in a cluster. The configuration file is XML that is parsed as such by the engine (into a Document object) of the application and so is a Java object, thus it can be placed into the DistributedMap.
Looks like a clean solution. Thanks all for reading and your replies.
http://www.ibm.com/developerworks/websphere/library/techarticles/0606_zhou/0606_zhou.html