Getting the upload folder in a Java servlet container - spring

Could be a silly question, but...
I have a Spring-based WAR application that runs 80% of the installations on Tomcat and the rest 20% on WebSphere.
I need to simply get the path of the folder where Spring's MultipartFilter (using Commons multipart resolver) stores files being uploaded. I have never set it manually, and it actually belongs to the Catalina work directory as I found out in my Tomcat installations.
For the moment, I just need to get that path. I have control of my application so no one is going to change it without notice.
I would like to know if there is a server-agnostic way to know where my Spring-based application is going to store Multipart files.
E.g. from this question I can see I can use catalina.base, but in Tomcat... not in JBoss or WebSphere. It could cost me a couple of if/else statements...

Spring tries to do it already when no default value is set
WebUtils.getTempDir(servletContext)
Which simply does:
return ((File)servletContext.getAttribute("javax.servlet.context.tempdir"));
So simply if no one overrides that location in the filter properties (and that is my case) I can rely on the default.
More in general, one may have to inspect the instance of DiskItemFileFactory to get the path to the repository

Related

Can you replace a Spring Boot jar while the application is running?

In our Linux environment applications are restarted periodically (the reasons aren't important here). It would be convenient for us to deploy new versions of an application by copying the application Spring Boot jar on top of the existing (old) jar thereby overwriting it and then simply wait for the application to restart (that is, the JVM running the application to restart).
However, this seems to not work. We get different kinds of errors - sometimes the app just hangs, sometimes we get a ClassNotFoundException. It's as if Spring Boot (or something inside Spring Boot) reopens the jar and expects it to be the same one it was when the application was originally started.
We had a look through Spring's common application properties, but didn't see anything appropriate. Is there a way to make this work? When we were using WAR files we configured the servlet container to unpack the WAR file and run from the unpacked version. Can we do something similar with Spring Boot?
First of all the errors you are experiencing can come from multiple sources. Usually replacing the file from a process is not a big problem as the whole file is loaded into memory before execution. Java is a little bit different, because the actual process that is running is the JVM and it only loads the jar file from disk. The JVM loads classes only on demand, this means if there was any class that was not loaded before it will try to load it and most likely fail, if the jar file is different. In the case of spring boot there are also other resources (such as HTML files) inside the jar file that are dynamically loaded.
You mentioned you are using a linux environment. If you can just replace your startup with a script you can just copy the jar and start it from the copied location:
#!/bin/bash
JAR_NAME="spring-boot.jar"
NEW_JAR_NAME=".$JAR_NAME" # Use an appropriate name here
cp $JAR_NAME $NEW_JAR_NAME
java -jar $NEW_JAR_NAME
rm $NEW_JAR_NAME
Now every time you start the application a copy is being made and started from there. You can replace the original jar and on the next restart the new application will load.
You coud also use rsync instead of cp to avoid copying the same jar twice, if the application is restarted multiple times without changing the jar.
It would be convenient for us to deploy new versions of an application
by copying the Spring Boot jar on top of the existing (old) jar and
then simply wait for the application to restart
Why would you do such a thing to yourself? You are trying solve a usecase that's against best practices, sound like asking for trouble just to avoid an app restart. When you are doing a deployment, you need to make sure the deployment went through, otherwise how will you troubleshoot if something goes wrong in your application, you will have one more variable in hand when you troubleshoot, i,e the uncertainty of current version of the code.
If you are having downtime while deploying (I am assuming thats why you want to limit the restarts), why don't you bring up another instance with the newer version of code and once its healthy shutdown the old one

CVE-2022-22965 - Tomcat Specific

I am trying to understand the Spring posted description of the problem and resolution alternatives
https://spring.io/blog/2022/03/31/spring-framework-rce-early-announcement
However, I do not understand why this would be Tomcat specific. Wouldnt the same issue exist for war files deployed to Jetty or Wildfly?
This particular exploit demostration is based on the custom custom implementation of one of tomcat specific classloaders having referrence to the servlet environment context. This is why this demo is tomcat specific especially that is exploits the fact that one of the logger valves is the first one in the processing pipeline (this is used to write custom jsp code as a log file in webapps root)
Also it requires Java9+ as it uses access trough class.getModule() which is not present in earlier versions

best way to read a file in Spring Boot

I have a spring boot application that currently runs in embedded Tomcat. I have a file, states.csv, that I want to parse on startup and seed my states database table (I tried via liquibase but that refuses to work).
I put the file in resources/main/ and that appears to work fine. My question is, if I decided against embedded Tomcat in the future (say moving to AWS or a regular Tomcat), is this still the best location to keep files for use?
I don't want to code myself into a corner if there is a better way to do this.
This depends entirely on how you're reading the file. As long as you're grabbing it out of the classpath, you should be fine. (And I've run single-jar applications on both basic AWS VMs and Cloud Foundry on EC2 with no difficulty at all.)

Can I create a transient configuration in OSGi using the ConfigAdmin?

I'd like to create a Configuration object in OSGi, but one that won't be persisted, so it won't be there when the framework is restarted. Similar to START_TRANSIENT for bundles.
Some background: I've got an OSGi (Felix) based client side application, deployed over OBR. The configuration object I'm talking about effectively boots the application. That works fine, but sometimes the content has changed while the context was stopped. In that case, it boots the application as OSGi revives all bundles and adds all configuration options. Then I inject the correct configuration, the application stops and then restarts again.
So it does actually work, but the app starts twice, and I can't get access to the framework before it reconstructs its old state.
Any ideas?
As BJ said there is no standard support for this in the Configuration Admin spec.
However the Felix implementation supports two features which may help you. First, you can set the felix.cm.dir property which configures where the configadmin saves its internal state (which by default will be somewhere under the Framework storage directory). You could set this to a location that you control and then simply wipe it every time you start OSGi (you could also wipe out the entire OSGi Framework storage directory on every start... some people do this but it has wider consequences that what you asked for).
Second, if you need a bit more control, Felix ConfigAdmin supports customising its persistence with a PersistenceManager service. You could probably implement this and return empty/doesn't-exist for the particular pids that you want to control.
The OSGi Config Admin spec does not support this. I also do not know of a non-standard means either for any of the CM impls I am familiar with.
Ok, what I did in the end was the following:
I created a special really small 'boot' bundle, which I do not provision from OBR, instead, I install it from the classpath.
That bundle controls the configuration, and I use START_TRANSIENT the moment I really want to load that configuration.
Not exactly pretty, it gets the job done. I do think transient configuration would make sense to have in OSGi.

Spring in production

What is the best practice to make changes in beans.xml file in production environment?
Lets imagine Hello World application with one Interface and 2 Implementations. After creating jar and running JVM how can we change implementation in beans.xml without opening jar and reassembling it afterwards?
Is it any trick that permits having beans.xml outside the jar, but without knowing the full file-system path?
On top of suggestion made by OrangeDog, I would suggest considering leaving the beans.xml inside your deployed application AND using the PropertyOverrideConfigurer mechanism.
Configure an override configurer to point to some fixed path outside of the application, something like /opt/configuration/something/override.properties would be ideal. If you can't use an absolute path, you can always try to play with file:../../.. style of paths. Then you can list only the changed values within the override.properties file.
Don't have the XML in a JAR. Your application should be deployed in at least a WAR, which the app server will probably "explode". The folder WEB-INF/classes will be added to the classpath. You can make changes to the exploded XML here and the app server should detect this and reload the app.
Edit:
If you are using plain Java SE, you can use a system property to pass the location of the XML file. System.getProperty("property") in code and -Dproperty=value on the command line.

Resources