Add external properties file packaging war Spring Boot - java

I have .properties file with secured information such as database password ,username and so on, this file locate outside of src/resources folder.
Is it possible to add this file to war file on packaging step
Like:
mvn clean package -DAddResource=/home/user/secured.properties

Two possible solutuions:
1) As I use jenkins , it's possible to use File Plugin , which dynamically add new file to your project
2) Second one , and this is the worst one , you can add spring property location directly to Tomcat in setenv.sh
JAVA_OPTS="$JAVA_OPTS -Dspring.config.location=/home/site/site/site.properties"
The main disadvantage is this file will be the same for all wars you deploy inside Tomcat

Related

Read external .properties file from the install directory (not the current directory)

I am distributing a Spring Boot application as a zipped "bootJar" using the Gradle Application plugin and the "distZip" task. The end-user will get the zip file, unzip it, and run it by just typing "myApp" (a shell script nicely created by the plugin).
I would like the end-user to create a "myapp.properties" file (a name I chose) and put it in the installation directory, or a "config" directory under the installation directory.
Suppose I set up my embedded (in the jar) application.properties file as follows:
spring.config.import = file:./myapp.properties will only read from the current directory
spring.config.import = file:/etc/myapp.properties will read from the specified directory -- but I don't know what this is at build time (the end-user determines it at installation time)
How can I set up my application so that Spring Boot can read properties from an external file whose location is specified later?
NOTE: I know I can play around with the generated scripts to pass in environment variables or Spring Boot properties, but I was hoping to do this completely within Spring Boot so I don't need to modify the nicely generated shell scripts.
spring.config.import = file:./myapp.properties will only read from the
current directory spring.config.import = file:/etc/myapp.properties
will read from the specified directory -- but I don't know what this
is at build time (the end-user determines it at installation time)
Why overcomplicate this.
Place inside the jar all the properties that you want to be statically configured as default values when you build the application.
Embedded application.properties
server.port = 8080
prop1.element = something
Then the client can create another file application.properties and place it in the same directory with the jar and define more properties which are not already defined.
prop2.element = something2
prop3.element = something3
By default Spring Boot will load properties both from the embedded file as well from the file in the current directory where the jar is placed during startup.
In the external application.properties you can also overwrite properties existing in the embedded application.properties. So if the external file in the current directory same as the jar is the following
prop2.element = something2
prop3.element = something3
prop1.element = something4 <--- this value here will overwrite the value 'something' from embedded file
According to spring doc
SpringApplication will load properties from application.properties
files in the following locations and add them to the Spring
Environment:
/config subdirectory of the current directory.
The current directory
classpath /config package
The classpath root The list is ordered by
Precedence (properties defined in locations higher in the list
override those defined in lower locations).
After having more input from the comments, it seems that you face another issue as well. You start the application from command line from another directory so that is counted as the directory where spring will look for the external configuration instead of where the jar is placed.
So for example let's say that the jar is placed inside the target folder that exists in current directory. You start the application using the following command:
java -jar target/demo-0.0.1-SNAPSHOT.jar
But then the external application.properties existing inside target folder is not loaded from spring because you executed the command from another directory. This can be solved if you start the application in the following way
java -jar -Dspring.config.additional-location=./target/ target/demo-0.0.1-SNAPSHOT.jar
This should not be difficult as you already provide the path where the jar exists in the command line.

How to force Tomcat doesn't write data (like logs, temp, ets) to its own root folder?

I'd like to create a desktop standalone application from my Java/Spring web application. I created MSI-installer that copy all required files to C:\Program Files (x86)\App. But tomcat doesn't have permission and can't write to its own folder. How I can configure tomcat so it would write all app-specific data to other folder? I wouldn't like to install my app to C:\App or user dir.
java.io.FileNotFoundException: C:\Program Files (x86)\App\tomcat\logs\catalina.2016-06-18.log (Access denied)
By setting the environment variable CATALINA_BASE to another directory in your tomcat start script you can configure Tomcat to read/put the working data, configuration and stuff from/to another location. If CATALINA_BASE is set, Tomcat will use the folders %CATALINA_BASE%/bin, %CATALINA_BASE%/conf, %CATALINA_BASE%/logs, %CATALINA_BASE%/temp, etc. for the current instance of Tomcat. This is described in more detail in the Advanced Configuration - Multiple Tomcat Instances section of the RUNNING.txt file in Tomcat's root folder.
If you are planning to ship Tomcat with your application and put all Tomcat files to some user choosable folder you should set CATALINA_HOME to this folder. Tomcat will then use this folder as base directory for everything.
However I think, as you mentioned to ship a standalone application based on Spring, you should seriously take a look at Spring Boot. This will allow you to ship a single fat jar containing all of your application's dependencies (including Tomcat). And this application can simply be started by executing the jar file.
If it's just about the log and temp files, you can set the Java system properties java.util.logging.config.file and java.io.tmpdir in the setenv.bat file under %CATALINA_BASE%/bin to make Tomcat use a custom logging configuration and a different temp dir, respectively. That is the file would look something like this:
set CATALINA_OPTS="-Djava.util.logging.config.file=file:///c:/path/to/log/config.properties"
set CATALINA_OPTS="%CATALINA_OPTS% -Djava.io.tmpdir=c:/path/to/temp/dir"
Find and update all occurrences of "$CATALINA_BASE"/logs/catalina.out to custom path in catalina.sh script.

Difference between deploying WAR and Build folder

Question 1: May I ask what is the difference between deploying a java webapp with it's WAR file vs just copy/pasting the build folder into tomcat webapp folder?
Question 2: Somehow I am told to deploy my project just by renaming my /build/web folder to /build/, then copy and paste this folder into tomcat/webapp folder. Tomcat did serve the web app and I could access it via url. But the problem is that I suspect my System variables were not set. I start up a servlet and put this code in this init(ServletConfig config) method:
System.setProperty("LogPath","D:/Test/logs");
And doing this in my log4j.properties
log4j.appender.file.FILE=${LogPath}/wrapper.log
wrapper.log is not found in the designated directory but a stdout.log is found in tomcat/logs folder.
I am sure the init() method was fired because I have a quartz scheduler there. I am suspecting that my System.setProperty was not set. Any hint?
Update: With all the same source code, I have no problem if I am deploying with a WAR file. The ${LogPath} in log4j.properties work as expected.
Let me answer you the first question.
WAR file is a zip archive with different name. When you deploy this file to the Tomcat server, it unpacks this file to its folder as you would do it by copy-paste. If you are just developing your own project in your own environment and you don't want to distribute it, you don't need to create a war file. But if you want to distribute this project, I recommend you to create a war file. One file is easier to be sent.
Read more on Wikipedia http://en.wikipedia.org/wiki/WAR_%28file_format%29

How to update xml file in war file?

I have war which working in production. I need to change the web.xml and again i need to make war file to deploy.Since we are changing xml file, so no need compliation at all..But i don't have source code to create war file again.
if change the xml file which will work again ? if yes how to create war file in command prompt ?
WARs are just zip files with .waras extension, so you just have to :
extract the WAR into some directory
replace web.xml in WEB-INF
zip the directory content into a file using the same filename than before.
BTW, try to deploy your repackaged WAR into some production-like environment to test if application is running like you want.

"log4j:WARN Please initialize the log4j system properly" error

I have a web application, in which one of the JSPs contain:
PropertyConfigurator.configure(System.getenv("MY_HOME") + "/cfg/log4j.properties");
I double-checked that MY_HOME is setup
The Tomcat web server says:
log4j:WARN No appenders could be found for logger (com.mycompany.data.JobData).
log4j:WARN Please initialize the log4j system properly.
The same setup works fine in one of the other servers.
Any hints?
The problem is that no logs are created
Not related to your answer, but this helps too.
If it's a web application, the easiest way is to make sure that your log4j.properties is situated in WEB-INF/classes folder in your WAR file. When your application will be deployed, log4J will be configured.
The PropertyConfigurator must be called before anything in your system attempts to log to avoid this warning. You may find setting the log4j configuration on the command line more reliable.
Or you could ignore the warning. ;)
BTW: You don't want to call this method too often, ideally only once.
You can try this, its helps to me.
http://www.log4j.ru/articles/HelloWorld.html
I was able to find the solution to this problem running a Eclipse Dynamic Web Project in Apache Tomcat 6. Bascially, you need to load the log4j properties file out of your context.
Two basic steps
(1) Get the log4j.properties file into the "class directory" of the war file.
(2) Read the log4j properties file out of the current context. I found the best way to do this is to access the current thread's context and work from there.
For the first step above, alter the Eclipse build process to add an additional directory that will eventually load into the WEB-INF/classes directory in the war file. Specifically....
(1) In Eclipse, right click your project in the project explorer, select 'New'->'Folder'. You can name the folder anything, but the standard in this case is 'resources'. The new folder should appear at the root level of your project.
(2) Move the log4j.properties file into this new folder.
(3) Right click the project again, and select 'Build-Path'->'Configure Build Path'. Select the 'Sources' tab. Click the 'Add Folder' button. Browse to find your new folder you created in step (1) above. Select 'OK'.
(4) Once back to the eclipse Project Explorer view, note that the folder has now moved to the 'Java Resources' area (ie it's no longer at the root due to eclipse presentation abstraction).
(5) Clean build your project.
(6) To validate that the .properties file now exists in WEB-INF/classes in your war file, export a war file to an easy location (right click Project -> Export -> War file) and checkout the contents. Note that the log4j.properties file now appears in the WEB-INF/classes.
Now for the second step above, accessing the context to read the file. Add the following code where attempting to read the file. Note that this reads this out of the war file context, so this 'should' work as the war file moves from server to server.
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
PropertyConfigurator.configure(classLoader.getResourceAsStream("log4j.properties") );

Categories