Make Java app reload its config file while running - java

Consider a Java standalone uberjar, which acts as a HTTP server and is run as a Linux service. Some of its functionality depends on an external config file, which might change once in while.
I try to avoid restarting the app every time the config changes. How could this be properly done? I immediately thought of sending a SIGHUP. Could this be caught by java app? Or maybe there is another way to achieve this?

Assuming the configuration file is accessible on the local file system, and the location is known, why not use the Watch Service?
https://docs.oracle.com/javase/tutorial/essential/io/notification.html

I would use HTTP for sending the command to reload the config file. This will require introducing a special HTTP request (for example, a custom header X-Uberjar-Reload-Config that will trigger the operation when used with the root URI). I would set the value of that header to the MD5 or SHA1 hash of the config file, so that the reloading is performed only if the submitted hash sum matches that of the config file.

Related

Accessing external files on network directories when deployed with microservice Jar file in Spring Boot

So I have a microservice app that does image processing with ImageJ which I have created a microservice using spring boot.
Often the image I am trying to load is coming from a samba share mapped to a directory like p:/
I have an issue that is ONLY happening when I execute the spring boot app as a JAR directly. If I execute it directly from STS using the tool executors it works fine. As well, the file is readable, viewable etc.
File f = new File("P:\\Stamps\\_Temp\\Img001.jpg");
BufferedImage image = ImageIO.read(f);
This will result in
javax.imageio.IIOException: Can't read input file!
at java.desktop/javax.imageio.ImageIO.read(ImageIO.java:1308) ~[na:na]
For debugging purposes I had it print out the .exist() and .canRead() - when executed in STS (Eclipse) these both return true, however from the JAR it will return false. More over if I try to access the image directly from a local folder (say c:\my-images) it works fine. So my assumption is there is some thing restricting access to these Network shared files when accessed from within a Jar (only).
I have not been able to find any reference information via searches to this on the usage of File so I am wondering if there is a spring boot configuration that is blocking this access (mainfest setting etc), or if it is a restriction of executing class byte-code from within a JAR?
So networked Mapped Drives in Windows can be accessed if you track back to the remote name and replace that drive letter with the appropriate mapping name. This thread covers an example where they do that: https://gist.github.com/digulla/31eed31c7ead29ffc7a30aaf87131def they key here is to replace the "P:" with "\server\path"
Again does not explain why this fails via Jar access vs. class exploded access, but at least it covers a workaround. For my use I might just simply use a mapping file since while I use the Network Mapping, I do not know how common this would be for other users and asking them to set some configuration in application.properties does not seem ridiculous for those cases. Still if anyone has insights into WHY we get different behavior inside and outside the Jar execution I'd be curious (or whether there is some spring-boot property in the manifest that needs to be set)

Link to properties file outside webservice

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

Tomcat directory to save information across restarts and redeployment

I have the requirement to save some information across restarts and redeployments, i.e. write it to a file when Tomcat is shut down and restore it from the file when it is started. It's similar to the way Tomcat saves session information across restarts (see Persistence Across Restarts).
What's the correct directory for such a file?
What's the API to get the path to this directory?
I'm looking for a solution that works on different operation systems, works across redeployments and does not require any setup or configuration tasks. It should be as simple as Tomcat's session persistence, which just works without any configuration.
Use ServletContextListener - Interface For handling your backup plan.
ServletContextListener - contextDestroyed(..) & contextInitialized(..)
And for Handling Path while store file inside Tomcat-server,
Use this code for retrieving path, request.getRealPath("/").toString()
Above getRealPath("/") will provide you server's log directory path. please change it accordingly whatever nearest you want.
Let me know whether this help in your scenario or not ?

persisting database connection parameters in java webapps

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.

What causes duplicate requests to occur using spring,tomcat and hibernate

I'm working on a project in Java using the spring framework, hibernate and tomcat.
Background:
I have a form page which takes data, validates, processes it and ultimately persists the data using hibernate. In processing the data I do some special command (model)
manipulation prior to persisting using hibernate.
Problem:
For some reason my onSubmit method is being called twice, the first time through things
are processed properly. However the second time through they are not; and the incorrect
information is being persisted.
I've also noticed that on other pages which are simply pulling information from the data
base and displaying on screen; Double requests are happening there too.
Is there something misconfigured, am I not using spring properly..any help on this would
be great!
Additional Information:
The app is still being developed. In testing the app I'm running into this problem. I'm using the app as I would expect it to be used (single clicks,valid data,etc...)
If you are testing in IE, make note that in some versions of IE it sometimes submits two requests. What browsers are you testing the app in?
There is the javascript issue, if an on click handler is associated with submit button and calls submit() and does not return false to cancel the event bubble.
Could be as simple as users clicking on a link twice, re-submitting a form while the server is still processing the first request, or hitting refresh on a POST-ed page.
Are you doing anything on the server side to account for duplicate requests such as these from your users?
This is a very common problem faced by someone who is starting off. And not very sure about the application eco-system.
To deploy a spring app, we build the war file.
Then we put it inside 'webapps' folder of tomcat.
Then we run the tomcat instance using terminal (I am presuming a linux system).
Now, we set up env in that terminal.
The problem arises when we set up our environment for the spring application where there can be more than one war files to be deployed.
Then we must cater to the fact that the env must be exclusive to a specific war file.
To achieve this, what we can do is create exclusive env files for every war. (e.g. war_1.sh,war_2.sh,.....,war_n.sh) and so on.
Now we can source that particular env file for which we have to deploy its corresponding war. This way we can segregate the multiple wars (applications) and their environment.

Categories