tomcat7 doesn't read context xml file - java

I would like to specify context for db in xml file.
<Context path="/db3" docBase="C:/my/workspace/db3/">
<Resource name="jdbc/ksidb" auth="Container"
type="javax.sql.DataSource"
description="Books"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/ksidb"
username="root"
password="root"
maxActive="20" />
</Context>
I've read that I should copy that file to /webapps tomcat catalogoue. I did this but tomcat7 doesn't read the file. Do you know why? What to do? Thx.

What you read is wrong. I'd question other advice from that source if it told you something so completely false. Per the Tomcat docs, your options for placing the context configuration are as follows:
In an individual file at /META-INF/context.xml inside the application files. Optionally (based on the Host's copyXML attribute) this may be copied to $CATALINA_BASE/conf/[enginename]/[hostname]/ and renamed to application's base file name plus a ".xml" extension.
In individual files (with a ".xml" extension) in the $CATALINA_BASE/conf/[enginename]/[hostname]/ directory. The context path and version will be derived from the base name of the file (the file name less the .xml extension). This file will always take precedence over any context.xml file packaged in the web application's META-INF directory.
Inside a Host element in the main conf/server.xml.
I highly recommend you visit the linked docs to learn more about the correct way to configure Tomcat.

Related

META-INF/context.xml causing problems in my Java Webapp

I'm deploying a simple Java 7 (I used Maven for project set-up, dependencies, etc) web app to Tomcat 8 and I have a META-INF/context.xml that I need to specify my database resource:
project/src/main/resources/META-INF/context.xml
<xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource"
maxTotal="100" maxIdle="30" maxWaitMillis="10000"
username="root" password="root" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://127.0.0.1:3306/javatest"/>
</Context>
When I remove this META-INF/context.xml file from the project, I am able to access my jsps but, of course, they return errors since my datasource is missing. However, when I include META-INF/context.xml back to the project, all resources that I try to access give me a 404. Why does it behave this way?
For reference, I am trying how to use a JNDI data source by following this guide. I did all the steps necessary in that project
Are there any exceptions when the server is starting?
If the jdbc driver is not bundled in WEB-INF/lib and not in CATALINA_BASE/lib then it can't find the class. That would most likely result in a startup failure.
Check catalina.out (if you are on unix) or CATALINA_BASE/logs/localhost/catalina.date.log
Edit
Just noticed you have src/main/resources/META-INF
Try src/main/webapp/META-INF/context.xml ...
Do not remove the META-INF/context.xml because it is the default configuration for the project! Also do not enter production-password into the default META-INF/context.xml!
Use copyXML="true" instead! On first deployment to tomcat the META-INF/context.xml is copied permanently into tomcat/conf/Catalina!
Set to true if you want a context XML descriptor embedded inside the application
(located at /META-INF/context.xml) to be copied to xmlBase when the application is
deployed. On subsequent starts, the copied context XML descriptor will be used in
preference to any context XML descriptor embedded inside the application even if the
descriptor embedded inside the application is more recent. The flag's value defaults to
false. Note if deployXML is false, this attribute will have no effect.
After first deployment update tomcat/conf/Catalina/webappname.xml to productive database informations.
Any redeployment will keep using the tomcat/conf/Catalina/webappname.xml.

How to set context path in context.xml

I have to deploy my app.war file in tomcat 7. The .war file name is followed by its version no.
Here I need to set up a context path, so that the actual url will contain only the app name(without version no).
My requirement is that, there should be no edit in server.xml.
My context.xml is as follows.
<?xml version='1.0' encoding='utf-8'?>
<Context path="/app" docBase="app-1.0" debug="0" reloadable="true">
<!-- Defines links to JNDI Data Sources -->
<!-- Thus the server determines database connection. -->
<ResourceLink
name="..."
global="..."
auth="Container" type="javax.sql.DataSource"/>
.....
.....
</Context>
The context.xml is placed inside the war at /META-INF folder.
Can anyone tell me where am i wrong.
All the elements are in the docs :
http://tomcat.apache.org/tomcat-7.0-doc/config/context.html#Naming
For your use case, you could do try :
change your version number format (from app-1.0.0.war to app##1.0.0.war
for instance)
place your war in another folder and create a app.xml
in $catalina.base/conf/Catalina/ which contains : <Context path="/app" docBase="/path/to/app-1.0" debug="0" reloadable="true">
avoid having your war with version number
Had a similar problem and it took me a long time to find the solution. It's on the tomcat site but it's difficult to find. This is what I did.
Your war file will be deployed to a folder under %CATALINA_BASE%. I put mine in a folder called deploy. (%CATALINA_BASE%/deploy)
You'll create an XML file with the path to your war file above and place it in %CATALINA_BASE%/conf/Catalina/localhost. The name of the xml file will become your context root. If the name of your war file is app1.2.war and you want your context root to be /app you're create app.xml:
<?xml version='1.0' encoding='utf-8'?>
<Context docBase="C:\tomcat7\Servers\server-app\deploy\app1.2" reloadable="false"/>
(My deployment is on Windows, you'll obviously have to adjust for a different OS.)
Also, let's for whatever reason say you want your context root to be /foo/Bar/app, change the name of your xml to foo#Bar#app.xml.

What is the Tomcat equivalent of JBoss' *-ds.xml?

In JBoss one can define a datasource with a *-ds.xml.
Is there an equivalent thing or procedure in Tomcat ?
Tomcat has several possibilities for configuring data sources. The main difference is if the data source should be available globally or just for a specific web application.
You can find all you need in the Tomcat documentation. Why didn't you look there right away?
In you configure the data source in context.xml file. Each webapp has one in META-INF folder. A data source will look like this:
<Resource name="jdbc/MyDS" auth="Container"
type="javax.sql.DataSource" username="root" password=""
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/mydb"
maxActive="8"
/>
You can also define a data source in the conf/context.xml file. In that case the data source will be available in all applications. You can reference a data source (e.g. in persistence.xml) like this:
<jta-data-source>java:comp/env/jdbc/JuddiDS</jta-data-source>

How to provide a context configuration for a web application in Tomcat?

I have a web application that relies on some resources and parameters to be configured after it is installed, like a JDBC connection.
What I have come up with is providing a META-INF/context.xml which is copied into [engine-name]/[server-name]/[app-name].xml by Tomcat when I deploy the application. This way all I am providing is a war file that can be copied into the appBase folder (webapps).
Tomcat's documentation says if there is such a file it won't be overwritten which is really great, since the changes made after deployment won't be lost.
But there is a subtle issue here:
Since we deploy the application by copying into webapps directory, Tomcat will first uninstall the existing application as well as the configuration file. This way the configuration file will be lost / overwritten which is not desirable.
Tomcat won't modify this behaviour as far as I know.
The question is:
Is there a way to work around this issue by installing the application in a way that Tomcat won't remove the existing configuration file.
Or, is there a better way of packaging the application?
Please note that we don't want to set autoDeploy to false and we cannot use human intervention for the installation (which rules out using Tomcat Manager web application).
If I get the configuration file out of .war file and copy it separately as [engine-name]/[server-name]/[app-name].xml, Tomcat will still associate it with my application and remove it once I copy a new .war file.
Another assumption is: We don't know in advance the values to the configuration. We will only provide a sample configuration (a placeholder, if you wish) while actual configuration will be performed at some time later (not necessarily in the installation time).
Thanks
The solution is simple: don't put configuration in your context.xml.
Here is a solution that we use (which works well for a number of diverse external customers):
We have a single war which will be used in multiple environments, webapp.war. We have three environments, development, integration and production. Integration and production are at the customer site. We don't know passwords and file paths for the client integration and production sites.
We use a combination of two things: JNDI lookup for database stuff and external properties files.
In the context.xml that is delivered in the war, we have a ResourceLink
<ResourceLink name="jdbc/webapp"
global="uk.co.farwell.webapp.datasource.MySqlDataSource" />
This gives a reference to a globally defined data source, which is defined in the server.xml for Tomcat.
<Resource auth="Container"
driverClassName="com.mysql.jdbc.Driver"
name="uk.co.farwell.webapp.datasource.MySqlDataSource"
password="xxx" url="xxx" username="fff" />
So the database details can be changed by editing the server.xml without changing the webapp.war. Crucially, this only needs to be done once for each server, not at redeploy.
In our spring configuration, to define the dataSource we have:
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/webapp" />
For other properties, we have a global application.properties file which is delivered along with the webapp.war, but is not part of the war. This is referenced by a -D on the command line to start Tomcat. -Duk.co.farwell.webapp.applicationDir="/usr/xxx/fff". We pick up the definition and read the properties file. The database stuff could be done this way as well, but we'd lose the pooling done by Tomcat.
Another thing: we don't have to rebuild if servers are moved, or if machines are changed for some reason. This is a matter for the customer and their infrastructure people.
I managed to resolve this issue somehow.
1- Install an exploded WAR directory somewhere outside Tomcat's appBase, let's assume it is in /usr/local/MyApp. [You can use a WAR file for this step instead of WAR directory, if your application runs from an unexploded war.]
2- Copy the context configuration file into [tomcat.conf]/[engine]/[hostname] directory, let's call it MyApp.xml. This file will point to the location of the application:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Context configuration file for my web application -->
<Context docBase="/usr/local/MyApp" privileged="true" antiResourceLocking="false" antiJARLocking="false">
<Resource name="jdbc/myapp-ds" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000" username="XXX" password="XXX"
driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/mydb" />
</Context>
3- You are now free to go and modify the configuration file.
4- Update the application by copying new version of your application in /usr/local/MyApp
Notes:
a) This solution applies to an unexpanded .war file as well, but since we use Spring's Log4JConfigListener it wouldn't run from an unexploded .war file. Tomcat doesn't explode .war files put outside appBase (webapps) folder.
b) This approach doesn't prevent you from having context.xml in /usr/local/MyApp/META-INF/context.xml since it will not be used by Tomcat in this configuration. You can use it in your dev environment, where you dump your .war file into the appBase (webapps) folder.
This is what I've got so far, still looking out for better solutions.
This is how we can manage to externalize webapp context from .WAR File
Place your .WAR file somewhere outside tomcat
Create a $APP_NAME.xml file into $TOMCAT_HOME/conf/[Engine]/[Host]/ directory.
Now file "$APP_NAME.xml" we just created need to have context definition and parameters + Any EnvironmentVariable you want specific to that context.
For e.g. I have an webapp called VirtualWebApp.
I will create file like VirtualWebApp.xml with below context definition :
<Context docBase="/home/appBase/VirtualWebApp" path="/VirtualWebApp" reloadable="true">
<Environment name="webservice.host" type="java.lang.String" value="1.2.3.4" />
<Environment name="webservice.port" type="java.lang.String" value="4040" />
</Context>
To access these environment variables you have to write below code(Just lookup) :
InitialContext initialContext = new javax.naming.InitialContext();
host = (String)initialContext.lookup("java:comp/env/webservice.host");
port = (String)initialContext.lookup("java:comp/env/webservice.port");
By referring to Apache Tomcat 5.5 Documentation:
In the $CATALINA_HOME/conf/context.xml file: the Context element
information will be loaded by all webapps
You could easily try this approach, it might work, but I'm not sure if this is a good solution especially if you are running multiple webapps on Tomcat.
I don't know how to modify Tomcat's behaviour but I could think of 2 different solutions:
different (parameterized) build scripts for each environment, so that you define a parameter called env to your build scripts and depending on the value it places the environment specific context.xml in your WAR during build.
Create an install script for each environment that first redeploys the WAR file (places it in webapps directory) and then makes modifications to the Tomcat installation depending on environment, e.g. different hostname for JDBC DataSource in context.xml.
I make heavy use of the latter approach as it works in enterprise environments. Separation of duties policies often prohibit the dev team from knowing e.g. production database passwords. Option #2 solves this problem because only IT operations have access to the environment specific install scripts after they have been created.
#n0rm1e: not sure if tomcat provides any sort of solution for you problem. But one possible solution can be:-
create an ant script with following steps:
i) Check existence of .xml file in [engine-name]/[server-name] directory. If it exists, take a back up of this/rename it.
ii) copy your war file to tomcat webapps. Restart tomcat server.
iii) copy backup-ed configuration file back to [engine-name]/[server-name] directory

Relative path to SQLite DB in context.xml

Is it possible to use a relative path to an SQLite database file in the context.xml file of a Java web application?
At present, I have:
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/mywebapp">
<Resource name="jdbc/mydb" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="myusername" password="mypassword" driverClassName="org.sqlite.JDBC"
url="jdbc:sqlite://Users/me/NetBeansProjects/MyApp/web/my.db"/>
</Context>
As you can see, the url attribute of the Resource tag currently specifies an absolute path to my.db. However, I am working on this project with a small team of developers as a class project. We are sharing the code through Subversion and currently, every time one of us updates our project, we have to manually replace the above path with the correct path for our computer.
Thanks in advance.
UPDATE: It appears that relative paths are not relative to the context.xml file, but to CATALINA_HOME. Unfortunately that directory (where Tomcat is located) is in another user's home folder (1) to which I have ony read access:
(1) /home/myprof/Tomcat/bin/
(2) /home/me/NetBeansProjects/MyApp/web/my.db
I cannot include /me in the relative path because, as stated above, this project will run on multiple computers via a svn repository and the directory in which the project files are contained (2) will change. However, since all of the accounts are on a shared virtual network, CATALINA_HOME (1) will not change.
Also, how can I get the path to the database file my.db from the context.xml file above inside a servlet?
I have found following examples of using JDBC with SQLite:
For memory access:
jdbc:sqlite::memory:
For relative paths:
jdbc:sqlite:relative/path.db
For absolute paths:
jdbc:sqlite:/absolute/path.db
As a different approach: did you try to use jdbc:sqlite:~/myapp.db ? This should be a writable location on the computers of everyone running that application. (Although I've seen the evil that are read-only home directories.)
I'm not exactly sure if SQLite supports ~ in the database URL. I know H2 does, and I can nothing but recommend it as an embedded Java DB. If you don't want to change databases, you might want to see if Tomcat allows some parameter substitution in its configuration files, like ${user.home}. (Some preliminary Googling gives me mailing list results that seem to imply that's be case in at least server.xml, so it could be worth just trying it.)
I'm still not exactly sure what you're trying to achieve though: are you the one running the Tomcat instance, or is it a shared tomcat instance running under some system account?
You could also try to set up another world-writable location on the network to put the database in. Somewhere under /var/ maybe, or just a folder that's set to ug=rwx in one person's home directory.
I am still looking for a way to use a relative path to the database in the context.xml file.
However, I figured out how to get extract the path to the database from the context.xml file. It's not pretty, but it works. I couldn't figure out how to parse the context.xml file as XML so this ugly hack looks for a line beginning with "url=".
URL url = getServletContext().getResource("/META-INF/context.xml");
Properties props = new Properties();
props.load(url.openStream());
String strval = props.getProperty("url");
Pattern pattern = Pattern.compile("\\\W*\"(.\*)\"\\\W*");
Matcher matcher = pattern.matcher(strval);
matcher.find();
String constr = matcher.group(1);
if (constr != null)
this.jdbcConnectionString = constr;
I had the same issue with Spring and jdbc.properties I fix that by removing // and write the relative path
Try this
<?xml version="1.0" encoding="UTF-8"?>
<Context path="/mywebapp">
<Resource name="jdbc/mydb" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="myusername" password="mypassword" driverClassName="org.sqlite.JDBC"
url="jdbc:sqlite:web/my.db"/>
</Context>
I found the answer to my question here. The solution is to get the resource rather than try to parse the database URL out of the context.xml file.
This answer is already given by honzas. I am reiterating it to make it more clear (b/c I also didn't understand it at first).
jdbc:sqlite:relative/path.db
That is correct for a relative path. Notice the lack of a / before relative. That makes the path absolute. You can also use this:
jdbc:sqlite:./relative/path.db
The . refers to the current folder.

Categories