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
Related
There's a web application and a number of environments in which it works. In each environment it has different settings like DB connection and SOAP ends-points that in their turn are defined in properties-files and accessed in the following way:
config.load(AppProp.class.getClassLoader().getResourceAsStream(
PROPERTIES_FILE_PATH + PROPERTIES_FILE_NAME));
Thus the WAR-files are different for every environment.
What we need is to build a unified WAR-file that doesn't contain any configuration and works in any environment (for now, Tomcat instance) getting its configuration from outside its WAR-file.
The answer Java Web Application Configuration Patterns, to my mind, gives the full set of common approaches but with just few examples. The most attractive way is configuring JNDI lookup mechanism. As I can guess it allows to separately configure web-applications by their context paths. But couldn't find a simple (step-by-step) instructions in both the Internet and the Tomcat's docs. Unfortunately cannot spend much time on studying this complicated stuff in order to just meet so seemingly simple and natural demand :(
Would appreciate your links at the relevant descriptions or any alternative suggestion on the problem.
If its a case of simply deploying your WAR on different environment (executed by different OS user), then you can put all your config files in the user's home folder and load them as:
config.load(new FileInputStream(System.getProperty("user.home") + PROPERTIES_FILE_NAME));
This gives you the isolation and security and makes your WAR completely portable. Ideally though, you should still provide built-in default configuration if that makes sense in your case.
The approach we've taken is based on our existing deployment method, namely to put the WAR files in the filesystem next to the Tomcat, and deploy a context.xml pointing to the WAR file to Tomcat.
The context descriptor allows for providing init parameters which is easily accessible in a servlet. We've also done some work on making this work with CDI (for Glassfish and TomEE dependency injection).
If you only have a single WAR file deployed to this Tomcat instance, you can also add init parameters to the default global context XML. These will be global and you can then deploy the WAR file directly. This is very useful during development.
I have a webservice that uses Java, REST, Jersey and runs on Tomcat8. The webservice requires access to a database. Depending on where we are in the process the we may be using a testdatabase, production database or something else. Ideally we would like to be able to set which database to use without requiring a code change and recompile.
The approach we have tried is to have a properties file defining the database parameters and use an environment variable to point to the file. This has proved troublesome, first we've had a hard time defining system properties on the Tomcat server that we can read from the application, also it seems like all the files will have to be defined on the classpath, i.e already configured ahead of time and part of the codebase.
This seems like fairly common scenario, so I'm sure there is a recommended way to handle situations like this?
Zack Macomber has a point here. Don't enable your app/service to look up its settings dynamically.
Make your build process dynamic instead.
Maven, Gradle and friends all provide simple ways to modify output depending on build parameters and or tasks/profiles.
In your code always link to the same file (name). The actual file will then be included based on your task and/or build environment. Test config for tests. Production config for production.
In many cases a complete recompilation is not necessary and will therefore be skipped (this depends on your tool, of course).
No code changes at all. Moreover the code will be dumb as hell as it does not need to know anything about context.
Especially when working on something with multiple people this approach provides the most stable long-term-solution. Customizable for those who need some special, local config and most important transparent for all who don't need or don't want to know about runtime environment requirements!
We have a similar case. We have created a second web service on the same endpoint (/admin) which we call to set a few configuration parameters. We also have a DB for persisting the configuration once set. To make life easier, we also created a simple UI to set these values. The user configures the values in the UI, the UI calls the /admin web service, and the /admin service sets the configuration in memory (as properties) as well as in the DB. The main web service uses the properties as dynamic configuration.
Note: we use JWT based authorization to prevent unauthorized access to /admin. But depending upon your need you can keep it unsecure, use basic HTTP auth or go with something more detailed.
Not sure if in this particular case it is wise, but it is possible indeed to create a .properties file anywhere on the filesystem - and link it into your application by means of a Resources element.
https://tomcat.apache.org/tomcat-8.0-doc/config/resources.html
The Resources element represents all the resources available to the web application. This includes classes, JAR files, HTML, JSPs and any other files that contribute to the web application. Implementations are provided to use directories, JAR files and WARs as the source of these resources and the resources implementation may be extended to provide support for files stored in other forms such as in a database or a versioned repository.
You would need a PreResources element here, linking to a folder, the contents of which will be made available to the application at /WEB-INF/classes.
<Context antiResourceLocking="false" privileged="true" docBase="${catalina.home}/webapps/myapp">
<Resources className="org.apache.catalina.webresources.StandardRoot">
<!-- external res folder (contains settings.properties) -->
<PreResources className="org.apache.catalina.webresources.DirResourceSet"
base="/home/whatever/path/config/"
webAppMount="/WEB-INF/classes" />
</Resources>
</Context>
Your application now 'sees' the files in /home/whatever/path/config/ as if they were located at /WEB-INF/classes.
Typically, the Resources element is put inside a Context element. The Context element must be put in a file located at:
$CATALINA_BASE/conf/[enginename]/[hostname]/ROOT.xml
See https://tomcat.apache.org/tomcat-8.0-doc/config/context.html#Defining_a_context
I've just started working with Spring/java web. I'm wondering how to accomplish following scenario:
Let's say that I'm creating an application which supports file upload, uses a database connection and maybe a web service. This is an off-the-shelf system, so all the settings are customer specific and should be configured by customer's IT people on the deployment time.
More general in the web.xml file I would like to point the application working directory containing uploaded files, license key file, configuration files, other customer specific resources and maybe even fragments of spring context.
<context-param>
<param-name>workdir</param-name>
<param-value>/var/r2/</param-value>
</context-param>
In my application I would like use the workdir value in order to include configuration files ...
<import resource="wordir_param_value/settings.properties" />
context config fragments
<import resource="wordir_param_value/security.xml"/>
And how may I later use these values in the java code? What is "the best" approach in case like this anyway (off-the-shelf application config)?
Best Regards,
Alek
You can use Spring's property support for that. This allowed two different approaches:
Having a property file outside the application (at a fixed location), the admin can edit it, and the application loads it
In a Tomcat you can write properties in the application specific context.XML file
In the code use #value annotation to inject the properties in a variable.
In the spring XML file you use it with ${name}
Of course you need to configure the proprtyPlaceholderConfigurer
i'm trying to get the absolute path of my eclipse project :
so i write this;
File file= new File("");
System.out.println(file.getCanonicalPath());
projectPath=file.getCanonicalPath();
so it gives me the right path when i execute it in a class as java application C:\Documents and Settings\Administrateur\Bureau\ready code\JavaServerFacesProject
But when i try to use it in my web application it gives this :
C:\Documents and Settings\Administrateur\Bureau\eclipse\eclipse
So any idea how to do it
Many thanks
Reading a file from a web application is a classical pitfall, whenever you do this you will suffer.
Web apps (especially Java EE) are not thought out to use the file-system for read/write operation, they rely on the fact that the container (in your case Tomcat) knows how to get the needed resources.
So the basic advice is : don't do it.
But since I basically hate this kind of answers I will give you some advice.
Never use the working directory
You never know where your working directory is, and, more often then not, in any production system, the web-app has no right to write on the working directory.
For example, if you deploy your webapp to a tomcat server, run as a service on a windows machine, you'll find that your working directory is \Windows\System32
You really don't want to write some uploaded files there for example...
You have a few option, what I prefer is to set a path into the web-xml and possibly override it from server configuration (using context).
Second option, even better is, to save a path into a db-table accessed by the web app.
ex:
in the web.xml you set
<context-param>
<description>Uploaded files directory</description>
<param-name>file-storage</param-name>
<param-value>c:\app\storage\uploaded</param-value>
</context-param>
Then in the you server.xml (or you could use the context dir and place there a file with the following code) you override this setting in context.
<Context
<Parameter
name="file-storage"
value="E:\app\storage\uploaded"
type="java.lang.String"
override="false" />
</Context>
Check tomcat documentation
Third option, in the slightly happier situation, you want to write just some temporary file, there is the webapp working dir accessible as a servlet context param named :
javax.servlet.context.tempdir
If I where you I would go for the database table.
All this complexity is because you can have multiple instance of the same app on different instances of tomcat, even on different machines, and even different web application into the same instance, so there is no easy way to make a 'relative' path is all situations.
Most web-app resolve to serialize data on db (using lobs or similar objects), whenever there is such necessity, or to rely on some kind of service (FTP, cifs, nfs ...).
In Eclipse, you can set a Working Directory for your project in the Run Configurations dialog.
Have you tried setting a non-default one there?
(If you cannot set anything, you could try the JVM option suggested here: https://stackoverflow.com/a/7838900/1143126 )
Java webapps provide a convenient way to make them run: It’s suficcient to drop the jar file into tomcat‘s webapps folder or upload it using the tomcat manager. If the jar file is named foo123.jar, the web application is soon accessible under http://<host>:8080/foo123/. However, in the majority of cases, there is a problem with the configuration: It’s a good practice to store data in a database, but where can I store the database connection parameters? Usually you have to adapt some server.xml or web.xml or other configuration file to put it there, but this hinders making use of the automatic deployment for such an application.
A “simple to use” web application should request its required configuration on the first run, like a “setup” screen, and then keep it in some place where it survives a restart of the servlet container. Of course, for database connection parameters, storing them in the database is not an option.
Following the specs, the servlet container has to provide a directory that a web application has write access to. It can be determined using:
File tempDir =
(File) session.getServletContext().getAttribute("javax.servlet.context.tempdir");
The content of this directory is bound to the ‘servlet context lifecycle’, if I got it right this means it is empty after a server restart. If that is true, it cannot be used for my purpose.
Does anybody know some kind of best practice for that? I don’t want to reinvent the wheel.
In lack of a better solution, I would implement it this way: As I said, if you make use of the easy deployment means described above, the context path is derived from the jar file name. So I could imagine to make use of this for the database connection as well. In simple terms: If the web application foo123 finds a MySQL connection on localhost:3306 (the MySQL default port) and can connect to it with username foo123 and password foo123 and has permissions to access a schema called foo123 it always uses that on restart.
What do you think of that?
You could just use a context.xml file. That will let you store the config files on a server-by-server basis and that means that you'll never have to put that information in the code itself.
This example seems to sum it up rather nicely.