I've developed a small application using Spring Boot, which uses HSQLDB as a database to store users, for the time being. What I want to do is store the database within Maven's resource folder. My application.properties file contains the following configuration:
#...
spring.datasource.url=jdbc:hsqldb:file:src/main/resources/database/dashboard
#...
So, whenever I start the application with Java (right click on my Application's main() and Run As Spring Boot App), the database is stored right.
But, after packaging a WAR file with mvn clean install spring-boot:repackage, deploying it into Tomcat, e.g., and running it, the database is not stored within the exploded WAR.
My question is how can I tell spring.datasource.url=jdbc:hsqldb:file:* property to store the database within Maven Resources directory (which will point still after exploding the WAR)? Could I use some sort of environment variable as used in pom.xml?
EDIT
Given the answers by #Steve C and #fredt, I've realised that the database shouldn't be stored within the war. Instead, I'll store it within the user's Home dir spring.datasource.url=jdbc:hsqldb:file:~/tomcat_webapp_data/dashboard/database.. Thank you so much!
The directories and contents of a WAR file are read-only.
You can set the read_only flag in the HSQLDB database .properties file before including in the WAR. You access this kind of database with a jdbc:hsqldb:res:<path> URL.
If you want to store data in a persistent and updatable database, connect to the (at first non-existent) database within your application and set up its tables if they don't yet exist with data from a resource. You can then store data. The database path should be outside the directories that are used for jars and resources.
Contrary to one of the comments, HSQLDB is not limited to storing data in memory and can have disk-based tables, called CACHED tables.
You can include a variable in the database URL to pick up a pre-defined property from the web server. For example:
jdbc:hsqldb:file:${mydbpath}
See http://hsqldb.org/doc/2.0/guide/dbproperties-chapt.html#dpc_variables_url
Maven's src/main/resources directory is a build time path, not a runtime path.
If you're building a jar file, then everything in src/main/resources is copied to the root of the jar.
If you're building a war file, then everything in src/main/resources is copied to the root of the /WEB-INF/classes directory in the war.
Now, your JDBC URL jdbc:hsqldb:file:src/main/resources/database/dashboard is indicating a file with a relative path. At runtime this path is relative to the current working directory - and it's unlikely to exist at runtime anyway.
If you really want to build the database within your WAR, then given:
you're deploying an exploded WAR file (it's impossible to write to the content of the WAR file itself);
you really really want to store the database within the exploded WAR;
you want to put it in WEB-INF/database/dashboard (there's security implications if you store outside of the WEB-INF directory);
then you can compute the JDBC url using something like:
...
String databaseDirectoryName = servletContext.getRealPath("WEB-INF/database");
File databaseDirectory = new File(databaseDirectoryName);
if (!databaseDirectory.exists()) {
if (!databaseDirectory.mkdirs()) {
throw new RuntimeException("Failed to create database directory");
}
}
File databaseFile = new File(databaseDirectory, "dashboard");
String jdbcURL = "jdbc:hsqldb:" + databaseFile.toURI();
...
Getting that into your Spring configuration is an exercise for you; but using #Configuration and #Bean springs to mind as a way to do this - you just need to get access to the servletContext at Spring configuration time.
Related
My Maven project needs to load data to database, and the import.sql contains the following:
LOAD DATA LOCAL INFILE
`'/home/jack/ubuntu/bword/src/main/resources/Term.txt' INTO TABLE Term FIELDS TERMINATED BY '\t' LINES TERMINATED BY '\n' (id,name);`
The path used here is the absolute path on my machine. How can I specify a relative path to make it work? I tried these:
/bword/src/main/resources/Term.txt
../bword/src/main/resources/Term.txt
../bword/src/main/resources/Term.txt
../src/main/resources/Term.txt
None of these work. The file is located at src/main/resources, a default directory in a Maven directory.
I am using JBoss and hibernate, JPA.
IMHO you can't do it.
Your application is web application (I take a look on chat). Maven can package import.sql and Term.txt into the application. Both files are visible on classpath. Hibernate scans classpath, finds import.sql and execute it.
But when import.sql is proceed, the command
LOAD DATA LOCAL INFILE 'file_name' ...
is executed. 'file_name' is resolved against current working dir.
Is Term.txt visible in filesystem? I don't think so.
Does you application control current directory of JBoss process? No
Summary:
Term.txt is not visible as file on JBoss filesystem
LOAD DATA LOCAL INFILE needs file on JBoss filesystem
I have a web application which I deploy on Tomcat Server manually.
My property file with database credentials is not located in classpath. On startup I load it like this:
prop.load(new FileInputStream("C:\\application.property"));
Downback of this is that now I can move my code to linux based platform without changing the source.
If I put this file to classpath it will be packed inside war (with all credentials) and replaced every time I redeploy my application. Tomcat is deleting application dir and replace it with war content on redeploy.
The question is: How and where to put property file in classpath and ensure that this file will not be replaces/deleted by application server on application redeployment. And the file must not be inside war.
The thing which you are doing looks like anti-pattern. Do not store database connection credentials in external property file.
Database access credentials should be placed inside context.xml configuration file of your tomcat. This is called JNDI Resources and you can read about it, for example, here.
I have developed a web application which will create an xml file based on the user Input. It has some more functionality. I configured my application to store the xml file(s) in the project root folder. When I run it through eclipse It stores in the specified location. But If I manually put the war file in apache tomcat and run the application those newly created xml files are going into bin directory since I used relative path. Now I dont want it to be created under bin directory. I want those files to be created somewhere local in the system. Is there any way to do it ? Or else what is the best way to deal with those xml files. I am using spring MVC.
You could use a variable in your code would contain the first part of the path (the real location where you want to write the file). And inject the value of that variable from a properties file, that way you wouldn't hardcode anything, and still would be able to provide only the relative path in your code.
I'm using H2 embedded database for my application. I would like to contain everything the application needs in it's own Jar, including it's database if possible. My app does not need to create temp files or anything, so basically the user just runs the Jar.
Is it possible to embed a database inside a Jar, and be able to INSERT new records as well as just SELECT out?
EDIT: Just to clarify, I'm not looking to embed the H2 driver jar inside my distributable jar, I'm looking to embed the h2 database file (someDatabase.h2.db file) inside a Jar and still be able to write/read from that database.
If you wish to embed the myDatabase.h2.db file inside the .jar, you can do so, but you'll have read-only access to the database. As .jar files are read-only, you can't modify them and therefore can't execute INSERT, DELETE or any DDL command.
That being said, below is an explanation on how to embed it read-only.
According to H2's documentation:
The JDBC URL "jdbc:h2:~/myDatabase" tells the H2 Engine to look for a database file named myDatabase.h2.db in the home directory of the current user.
The JDBC URL "jdbc:h2:file:/myDatabase" tells the H2 Engine to look for a database file named myDatabase.h2.db in the current directory (where the java program was executed).
If you embed the h2.db file inside a .jar, it is not accessible in a plain way. It is only accessible as a file inside a zip file.
In order to make H2 uset it, you have to use a zip as URL:
jdbc:h2:zip:~/data.zip!/test
See more in "Read Only Databases in Zip or Jar File".
When you embed the file as a resource in the jar, you may get it's relative url. Using...
MyClass.class.getClassLoader().getResource("myDatabase.h2.db")
...you'll get something like:
jar:file:/C:/folder1/folder2/myJar.jar!/myDatabase.h2.db
You can then manipulate it as a String and pass as JDBC URL connection to H2.
I have a java desktop app and the issue of config files is vexing me.
What I want is for my distributable application folder to look like this:
MyApp/Application.jar
MyApp/SpringConfig.xml
MyApp/OtherConfig.xml
MyApp/lib
But at the moment SpringConfig.xml is inside Application.jar and I can't even find OtherConfig.xml programmatically.
I don't care how I set up the various files in my compilation path, so long as they end up looking like the above.
So..
where do i put the files in my dev setup?
and how do i access them programmatically?
thanks
the spring config file is related to the code and wiring of your application, hence it'd better be inside the jar, and should be subject to change by the users
(new File(".")).getAbsolutePath(); returns the absolute path of your jar - then you can load the OtherConfig.xml by a simple FileInputStream
if the SpringConfig.xml contains configuration data like database credentials, put them in an external application.properties and use a custom PropertyPlaceholderConfigurer to load the external file.
Answering the question "where do I put the files in my dev setup" is not possible because we don't know your environment.
Actually, if you want to be able to edit the config yourself (and not necessarily end-users), you can open the jar with any zip software (WinRAR for instance) and edit the config file from within the jar.
Update: as it seems you can't make the config files to be places out of the jar. Well, for a start, you can do it manually - whenever the .jar is complete, just remove the config file from inside and place it outside.
I typically create a structure where I have a src/ directory and then other directories exist at the same level. Some of those directories include:
lib/ - External Libraries
config/ - Configuration Files
resources/ - Various resources I use (images, etc)
At that same level, I then create an Ant script to perform my build so that the appropriate config files, resources, lib, etc are copied into my JAR file upon build. It has worked great for me up to this point and is a fairly easy to understand organizational structure.
Update: Accessing my config files is done, typically, by knowing their location and opening them up and reading them in the code. Because I use Ant to build, I make sure that my config files are in a location that I expect. So, for example, in a recent application I created, when I compile, my JAR file is in the top level directory (relative to the application release structure). Then, there is a "main" config file at that same level. And there is a "theme" config file that is in a themes folder.
To read the various files, I just open them up as I would any other file and read them in and go from there. It's nothing particularly fancy but it works well and it makes it easy to manually change configurations if I need to do so.
In dev mode, put them in source dir and they will be copied to your classes folder, you can then access them using classloader.
Example:
URL url = ClassLoader.getSystemResource("test.properties");
Properties p = new Properties();
p.load(new FileInputStream(new File(url.getFile())));
In Prod mode, you can make them part of your jar.