{"id":903,"date":"2015-02-01T06:57:46","date_gmt":"2015-02-01T06:57:46","guid":{"rendered":"http:\/\/mooredynasty.net\/?p=903"},"modified":"2015-02-01T07:16:57","modified_gmt":"2015-02-01T07:16:57","slug":"distributing-a-sqlite-database-in-a-tomcat-war-file","status":"publish","type":"post","link":"https:\/\/mooredynasty.net\/index.php\/2015\/02\/distributing-a-sqlite-database-in-a-tomcat-war-file\/","title":{"rendered":"Distributing a Sqlite Database in a Tomcat WAR File"},"content":{"rendered":"<p>Given a pre-existing Sqlite database \u2013 that\u2019s another story for another time \u2013 including it in a WAR file to be built by Maven and installed on Tomcat 8 is simple:&#160; simply include the database in the application\u2019s WEB-INF folder and presto, it\u2019s there!<\/p>\n<p>Referencing Sqlite in a Maven project is also simple \u2013 just add the dependency to the POM:<\/p>\n<blockquote>\n<p>&lt;dependency&gt;      <br \/>&#160; &lt;groupId&gt;org.xerial&lt;\/groupId&gt;       <br \/>&#160; &lt;artifactId&gt;sqlite-jdbc&lt;\/artifactId&gt;       <br \/>&#160; &lt;version&gt;3.7.2&lt;\/version&gt;       <br \/>&lt;\/dependency&gt;<\/p>\n<\/blockquote>\n<p>Unfortunately, Tomcat did not have a Sqllite library available to it, so I included the Sqlite library in the WEB-INF\\lib folder, which is part of the classpath for Tomcat applications.&#160; <\/p>\n<p>During the build, Maven packaged up the JAR into the WAR file and, after deployment, the redistribution libraries are extracted to the app\u2019s \/lib folder under Tomcat:<\/p>\n<p><a href=\"https:\/\/mooredynasty.net\/wp-content\/uploads\/2015\/02\/image.png\"><img loading=\"lazy\" decoding=\"async\" title=\"image\" style=\"border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px\" border=\"0\" alt=\"image\" src=\"https:\/\/mooredynasty.net\/wp-content\/uploads\/2015\/02\/image_thumb.png\" width=\"391\" height=\"233\" \/><\/a><\/p>\n<p>Practically done, I thought.&#160; But hold the celebration: Opening the database from the Java servlet is a more challenging problem.&#160; <\/p>\n<p>(Typical of Java, easy things are harder than they should be and should-be-easy things are a nightmare.)<\/p>\n<p>The root issue at this point is finding the Sqlite database on the Tomcat server.&#160; What should the file system path be in the connection string?&#160; On a foreign server, like the one my team will be using for our project, who can say where on disk the application and its resources will be?<\/p>\n<p>The database location is obviously relative to the application, so the problem seemed surmountable.&#160; .NET has simple mechanisms for an application to determine where it is running; Java less so.&#160; One of the answers to <a href=\"http:\/\/stackoverflow.com\/questions\/4279632\/how-to-configure-sqlite-in-tomcat-6\">a Stack Overflow question on the subject<\/a> helped me.&#160; The accepted answer is of no help since we can\u2019t count on a database file being deployed on the server, but MattC\u2019s answer was more useful:&#160; Use JNDI to read a configuration file and explode a Tomcat-relative path.<\/p>\n<p>Following Matt\u2019s advice seemed easy.&#160; First, add a META-INF\/context.xml:<\/p>\n<blockquote>\n<p>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;      <br \/>&lt;Context&gt;&#160; <br \/>&#160; &lt;Resource name=&quot;jdbc\/testdb&quot;       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; auth=&quot;Container&quot;       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; type=&quot;javax.sql.DataSource&quot;       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; driverClassName=&quot;org.sqlite.JDBC&quot;       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; url=&quot;jdbc:sqlite:${catalina.base}\/webapps\/sqlwebexample\/WEB-INF\/db\/test.db&quot;       <br \/>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; factory=&quot;org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory&quot;&gt;       <br \/>&#160; &lt;\/Resource&gt;       <br \/>&lt;\/Context&gt;<\/p>\n<\/blockquote>\n<p>Second, add a resource reference to the WEB-INF\/web.xml:<\/p>\n<blockquote>\n<p>&lt;resource-ref&gt;      <br \/>&#160; &lt;description&gt;CompanyDatabase&lt;\/description&gt;       <br \/>&#160; &lt;res-ref-name&gt;jdbc\/testdb&lt;\/res-ref-name&gt;       <br \/>&#160; &lt;res-type&gt;javax.sql.DataSource&lt;\/res-type&gt;       <br \/>&#160; &lt;res-auth&gt;Container&lt;\/res-auth&gt;       <br \/>&lt;\/resource-ref&gt;<\/p>\n<\/blockquote>\n<p>Third, use a JNDI context to look up the resource path and resolve the Tomcat root path macro by changing<\/p>\n<blockquote>\n<p>c = DriverManager.getConnection(&quot;jdbc:sqlite:.\/test.db&quot;);<\/p>\n<\/blockquote>\n<p>to<\/p>\n<blockquote>\n<p>Context ctx = new InitialContext();      <br \/>DataSource ds = (DataSource)ctx.lookup(&quot;java:comp\/env\/jdbc\/testdb&quot;);       <br \/>c = ds.getConnection();<\/p>\n<\/blockquote>\n<p>No problem.<\/p>\n<p>That is, of course, where the problems began.&#160; After making these changes, Maven was unable to build the project because the <em>javax.naming<\/em> library was not available to supply the JNDI classes.&#160; <a href=\"https:\/\/www.google.com\/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=1&amp;cad=rja&amp;uact=8&amp;ved=0CB4QFjAA&amp;url=http%3A%2F%2Fmvnrepository.com%2Fartifact%2Fjavax.naming&amp;ei=qsfNVJ2uBca8ggSHr4L4BQ&amp;usg=AFQjCNGF9uq8E4RIsFvQRTTGWI2YSZ_NHw&amp;sig2=MjV4n6EwA_FLyL4-4GOKtw\">Maven didn\u2019t have it either<\/a>, meaning I had to download it from Oracle manually and add it to the project\u2019s local Maven repository.&#160; <\/p>\n<p>This is yet another story, the short version of which is that I ended up with a C:\\Deve\\CS6440\\sqlwebexample\\lib\\javax\\naming\\jndi\\1.2.1\\jndi-1.2.1.jar file referenced by Maven.<\/p>\n<p>(This is also how I referenced the Microsoft SQL Server JDBC driver in yet another story, so the technique definitely has its time in the sun.)<\/p>\n<p>With JNDI in place Maven built the WAR file and for a moment my confidence was high.&#160; But I was quickly brought down to earth by this run-time exception:<\/p>\n<blockquote>\n<p>ClassNotFoundException: org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory\u2026<\/p>\n<\/blockquote>\n<p>WTF?&#160; I\u2019m in Tomcat, so surely it knows about its own libs.&#160; This one got confusing because there are at least 2 <em>dbcp<\/em> libraries being supported and several old versions as well and I found myself adding another JAR file to the local Maven repo before <a href=\"http:\/\/stackoverflow.com\/questions\/22518748\/classnotfoundexception-when-upgraded-to-tomcat-8\">an answer to this underappreciated Stack Overflow gem<\/a> clued me in to Tomcat 8\u2019s use of yet another version of the <em>dbcp<\/em> library in the META-INF\/context.xml file:<\/p>\n<blockquote>\n<p>factory=&quot;org.apache.tomcat.dbcp.<strong><u>dbcp2<\/u><\/strong>.BasicDataSourceFactory&quot;&gt;<\/p>\n<\/blockquote>\n<p>At this point the committed reader will note that Matt\u2019s information came from a question about Tomcat 6.&#160; A real Java developer probably would have caught this one much sooner.<\/p>\n<p>Anyway, another tweak, another WAR file, and another exception:<\/p>\n<pre><code>java.lang.AbstractMethodError: com.sqlite.jdbc.Connection.isValid(I)Z<\/code><\/pre>\n<p>WTF again!&#160; Scrounging about it seemed that the error had to do with connection pool validation and version 3 vs. version 4 drivers.&#160; Eventually I found this snipped in the Tomcat docs:<\/p>\n<blockquote>\n<p><code>validationQuery<\/code><\/p>\n<p>(String) The SQL query that will be used to validate connections from this pool before returning them to the caller. If specified, this query does not have to return any data, it just can&#8217;t throw a <code>SQLException<\/code>. The default value is <code>null<\/code>. Example values are <code>SELECT 1 <\/code>(mysql), <code>select 1 from dual <\/code>(oracle), <code>SELECT 1 <\/code>(MS Sql Server)<\/p>\n<\/blockquote>\n<p>So it was back to META-INF\/context.xml to add this attribute to the Resource tag:<\/p>\n<blockquote>\n<p>validationQuery=&quot;SELECT 1&quot; <\/p>\n<\/blockquote>\n<p>And with that, finally, success:&#160; a Java servlet app deployed to Tomcat with a pre-populated, embedded Sqlite database up and running!<\/p>\n<p><strong>Lesson Learned<\/strong>:&#160; However much Visual Studio and Eclipse may suck at times, they\u2019re a heck of a lot better than having to hand-configure this sort of business like I\u2019m doing now.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Given a pre-existing Sqlite database \u2013 that\u2019s another story for another time \u2013 including it in a WAR file to be built by Maven and installed on Tomcat 8 is simple:&#160; simply include the database in the application\u2019s WEB-INF folder and presto, it\u2019s there! Referencing Sqlite in a Maven project &hellip; <\/p>\n","protected":false},"author":6,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[15],"tags":[],"class_list":["post-903","post","type-post","status-publish","format-standard","hentry","category-development"],"_links":{"self":[{"href":"https:\/\/mooredynasty.net\/index.php\/wp-json\/wp\/v2\/posts\/903","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mooredynasty.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mooredynasty.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mooredynasty.net\/index.php\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/mooredynasty.net\/index.php\/wp-json\/wp\/v2\/comments?post=903"}],"version-history":[{"count":5,"href":"https:\/\/mooredynasty.net\/index.php\/wp-json\/wp\/v2\/posts\/903\/revisions"}],"predecessor-version":[{"id":908,"href":"https:\/\/mooredynasty.net\/index.php\/wp-json\/wp\/v2\/posts\/903\/revisions\/908"}],"wp:attachment":[{"href":"https:\/\/mooredynasty.net\/index.php\/wp-json\/wp\/v2\/media?parent=903"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mooredynasty.net\/index.php\/wp-json\/wp\/v2\/categories?post=903"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mooredynasty.net\/index.php\/wp-json\/wp\/v2\/tags?post=903"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}