How to define default context elements with Tomcat? - java

We deploy an application on tomcat 9 (apache-tomcat-9.0.22).
The official documentation (https://tomcat.apache.org/tomcat-9.0-doc/config/context.html) says it's possible to define default context elements but it's not working for us.
We need to define a datasource and a mail server. If we define this resources in conf/server.xml file in GlobalNamingResources it works.
<GlobalNamingResources>
<Resource name="mail" type="javax.mail.Session"... />
<Resource name="jdbc/mydb" type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver"... />
</GlobalNamingResources>
But in production, we cannot modify server.xml file. So we need to define this resources in an other file.
If we define resources in $CATALINA_BASE/conf/[enginename]/[hostname]/ROOT.xml file with a war named ROOT.war, it works :
<?xml version="1.0" encoding="UTF-8"?>
<!-- Context configuration file for my web application -->
<Context>
<Resource name="mail" type="javax.mail.Session"... />
<Resource name="jdbc/mydb" type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver"... />
</Context>
This solution could be satisfactory but our war file must have a different name than ROOT.war (like MyApp_v42.war) and it will change with every update. We cannot rename the xml file every time we update.
If we define resources in the $CATALINA_BASE/conf/context.xml file or in $CATALINA_BASE/conf/[enginename]/[hostname]/context.xml.default file like documentation says we obtain a javax.naming.NameNotFoundException.
Thanks in advance!

One solution is :
Define resources in conf/context.xml :
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource name="mail" type="javax.mail.Session"... />
<Resource name="jdbc/mydb" type="javax.sql.DataSource"... />
-->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
<Manager pathname="" />
</Context>
Use a deployment outside of the webapps directory, for example in wars/
Create an XML file ROOT.xml under the conf/Catalina/localhost/ that define the docBase attribute with a path relative to the webapps directory :
<?xml version="1.0" encoding="UTF-8"?>
<Context docBase="../wars/MyApp.war"></Context>
In this way :
the conf/server.xml file is not modify
the name of the war file is not necessary ROOT.xml
resources are defined in conf/context.xml
But :
you must have one file in conf/Catalina/localhost/ per .war
wars are not auto-deployed
if you change the name of the root war file, you must modify the docBase attribute in conf/Catalina/localhost/ROOT.xml file.

Related

porting web app to Tomcat: javax.naming.NameNotFoundException:

New user of Tomcat (8.5.9) on Linux CentOS 7 with Java SE 8. I must be making a simple mistake. This should be a textbook example how to configure a JDBC connection pool for tomcat.
I have this error:
javax.naming.NameNotFoundException: Name [jdbc/pool1] is not bound in this Context. Unable to find [jdbc]
Any idea what I could doing wrong? Tomcat states It is NOT recommended to place <Context> elements directly in the server.xml file. Thus, my setup:
$CATALINA_HOME/webapps/myapp/META-INF/context.xml is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource name="jdbc/pool1"
auth="Container"
type="javax.sql.DataSource"
username="xx"
password="xx"
driverClassName="oracle.jdbc.OracleDriver"
url="xx"
maxTotal="256"
maxIdle="8"
initialSize="4"
removeAbandonedTimeout="7200"
removeAbandonedOnBorrow="true"/>
<Resource name="jdbc/pool2"
auth="Container"
type="javax.sql.DataSource"
username="xx"
password="xx"
driverClassName="oracle.jdbc.OracleDriver"
url="xx"
maxTotal="256"
maxIdle="8"
initialSize="4"
removeAbandonedTimeout="7200"
removeAbandonedOnBorrow="true"/>
<ResourceLink name="jdbc/pool1"
global="jdbc/pool1"
type="javax.sql.DataSource"/>
<ResourceLink name="jdbc/pool2"
global="jdbc/pool2"
type="javax.sql.DataSource"/>
</Context>
$CATALINA_HOME/webapps/myapp/WEB-INF/web.xml is as follows:
...
<resource-ref>
<description>xxx</description>
<res-ref-name>jdbc/pool1</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<resource-ref>
<description>xxx</description>
<res-ref-name>jdbc/pool1</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
...
The code causing the exception:
Context context = new InitialContext();
DataSource ds = (DataSource)context.lookup("jdbc/pool1");
conn = ds.getConnection();
I have not modified $CATALINA_HOME/conf/server.xml at all. Did I configure something incorrectly, or am I missing setting another file up somewhere?
UPDATE 1
I tried adding the above ResourceLinks to the GlobalNamingResources tag in the $CATALINA_HOME/conf/server.xml file, then stopping/starting Tomcat, but I got the same error.
UPDATE 2
I then added the Resource tags from context.xml above also to the server.xml file (GlobalNamingResources tag), stopping/starting tomcat, and got same error.
UPDATE 3
I got everything working with Andreas' expert help (thanks!) by changing the way java calls the pool:
Context initCtx = new InitialContext();
Context context = (Context) initCtx.lookup("java:comp/env");
DataSource ds = (DataSource) context.lookup("jdbc/pool1");
conn = ds.getConnection();
Also, the ResourceLinks should not be in server.xml (they simply generate a warning in tomcat log).
Your $CATALINA_BASE/conf/server.xml file should contain the full <Resource> element. Remember to also add the JDBC driver jar file to Tomcat's $CATALINA_BASE/lib folder, since it is Tomcat, not your webapp, that needs it when the <Resource> is defined in server.xml.
Next, the META-INF/context.xml is a template that is used the first time your webapp is deployed. It gets copied to $CATALINA_BASE/conf/Catalina/localhost/myapp.xml, and is likely not updated/refreshed if you change META-INF/context.xml.
The .../Catalina/localhost/myapp.xml file should contain the <ResourceLink> element, mapping the name used by the webapp to the name used in server.xml. Keeping those two names the same is easiest, but not required.
Tomcat works fine without the <resource-ref> elements in WEB-INF/web.xml, but it's better if they are there, for compatibility with other Servlet containers.
Note: $CATALINA_BASE is usually the same as $CATALINA_HOME, i.e. the folder where Tomcat is installed, unless you explicitly configure it otherwise.
So, $CATALINA_BASE/conf/server.xml:
<?xml version='1.0' encoding='utf-8'?>
<Server ...>
...
<GlobalNamingResources>
...
<Resource name="jdbc/pool1" auth="Container" type="javax.sql.DataSource" ... />
<Resource name="jdbc/pool2" auth="Container" type="javax.sql.DataSource" ... />
...
</GlobalNamingResources>
...
</Server>
and $CATALINA_BASE/conf/Catalina/localhost/myapp.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<ResourceLink name="jdbc/pool1" global="jdbc/pool1" type="javax.sql.DataSource"/>
<ResourceLink name="jdbc/pool2" global="jdbc/pool2" type="javax.sql.DataSource"/>
</Context>
and place ojdbcXXX.jar in $CATALINA_BASE/lib.

Multiple context for java web application

I have a situation here i have an application in jsf-2.1 which is deployed as http://localhost:8080/myWebApplication and in "META-INF" i have context.xml which has the following configuration
<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/myWebApplication" />
Now i want to shorten the name without loosing context => 'myWebApplication' like '/mwp'
i tried to do the following but it did not work out as expected:
<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/myWebApplication" />
<Context antiJARLocking="true" path="/mwp" />
Please advise if it is possible or is there any workaround to achieve this.
Your application will (on your application server, not talking about vhosts or mod_rewrite on apache) only respond to:
The application name you have defined in your web.xml
If there is no such configuration in your web.xml, it will respond to the name of the war-file. If for example your application is called myWebApplication.war, it will respond to /myWebApplication.

When is the tag I added in context.xml gets read?

In the context.xml of Tomcat I added the following tag :
<Resource name="jdbc/MyDatasource" auth="Container" type="javax.sql.DataSource"
driverClassName="org.apache.derby.jdbc.ClientDriver"
url="jdbc:derby://localhost:1527/my_database;create=true"
username="me" password="me"
maxActive="20" maxIdle="10" maxWait="-1" />
When does the following tag gets read ? Is it read when i start the server ?
This configuration is read when the application is deployed. If you have auto-deploy enabled, Tomcat will deploy your webapp during startup.

connecting to derby database with tomcat as the server

How do i connect to derby database (that comes with the netbeans) ? I am using Tomcat as the server. Earlier i used the following statements to connect to the derby database,but then i used glassfish as the server.
Context context = new InitialContext();
DataSource ds = (DataSource)context.lookup("java:comp/env/jdbc/PollDatasource");
Connection connection = ds.getConnection();
But now using Tomcat as the server i am unaware how to do this.
Note : Tomcat and Derby are pre installed with netbeans IDE that i am using currently
In Tomcat find conf/context.xml, then edit and write something like this:
<Resource name="jdbc/PollDatasource" auth="Container" type="javax.sql.DataSource"
driverClassName="com.YourDriver"
url="jdbc:derby://localhost:1527/nameOfTheDatabase;create=true"
username="username" password="password" maxActive="20"
maxIdle="10" maxWait="-1" />
Note 1: With the above URL the driver will be org.apache.derby.jdbc.ClientDriver
Note 2 : You can also add the above information in META-INF/context.xml of your project. This becomes application specific.If you add the information in tomcat's context.xml that becomes global.
Note 3: Download the jar from this website.Download db-derby-10.9.1.0-bin.zip.It contains many files, including derby.jar and derbyclient.jar (along with much documentation).derbyclient.jar contains our friend org.apache.derby.jdbc.ClientDriver.class. derby.jar contains org.apache.derby.jdbc.EmbeddedDriver. Keep the downloaded jar in lib folder of Tomcat.
and in your application web.xml "resource-ref":
<resource-ref>
<description>my connection</description>
<res-ref-name>jdbc/PollDatasource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
You may want to look at these questions :
Isn't it necessary to mention the name of archive in the Resource tag?
When is the tag I added in context.xml gets read?
What are steps followed in the look-up? what is looked first web.xml or context.xml?
You need to:
1) Copy your derbyclient-*.jar to ${TOMCAT_HOME}/lib.
2) Edit your server.xml and add the following lines to the section GlobalNamingResources:
<Resource auth="Container"
driverClassName="org.apache.derby.jdbc.EmbeddedDriver"
maxActive="8" maxIdle="4"
name="jdbc/my-ds" type="javax.sql.DataSource"
url="jdbc:derby:mydb;create=true"
username="myuser" password="mypassword" />
3) In your context definition, add:
<Context docBase="myapp"
path="/myapp"
reloadable="true"
...>
<ResourceLink name="jdbc/my-ds"
global="jdbc/my-ds"
type="javax.sql.DataSource" />
</Context>
4) Restart Tomcat.
The example you have requires JNDI. See the relevant tomcat versions docs on setting that up.
Or use a connection string, here's a page from derby docs http://db.apache.org/derby/integrate/plugin_help/derby_app.html

where/how to setup configuration resources for Tomcat .war files

I have a source tree for a .war file that I need to modify so that I can add some application-specific configuration info (in this case a jdbc connection string, but I may have other properties-like resources). What are the best practices for where to put configuration info and how to access this from within the Servlet?
I'm guessing this Tomcat configuration reference has something to do with it, but my eyes glaze over when I try to read it.
For web app configuration you can place the config on the classpath somewhere. Then you can get to it from your application with getResourceAsStream or if you prefer Spring:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:my-config.properties</value>
</list>
</property>
</bean>
There are a number of places you can put the properties on the classpath in Tomcat. in order it looks at:
/WEB-INF/classes of your web application
/WEB-INF/lib/*. jar of your web application
$CATALINA_HOME/common/classes
$CATALINA_HOME/common/endorsed/*.jar
$CATALINA_HOME/common/i18n/*.jar
$CATALINA_HOME/common/lib / *. jar
$CATALINA_BASE/shared/classes
$CATALINA_BASE/shared/lib/*.jar
For example, if you put my-config.properties both in a .jar file and in WEB-INF/classes the one in WEB-INF/classes will be used. You could use this mechanism to default to test config and override prod config on prod servers.
For the specific case of a JDBC connection string, I would recommend using a Tomcat-managed connection pool instead. You can read more about doing this here:
http://tomcat.apache.org/tomcat-5.5-doc/jndi-datasource-examples-howto.html
It's more work, but I think in the long run it will serve you better.
Hmm. It looks like the easiest path to getting what I want on the Java side of the application is to use Servlet.getServletConfig().getInitParameter(parameterName) e.g. getInitParameter("myApp.connectionString");
But I don't know where to set this. The Tomcat docs talk about various permutations of context.xml but I want to make sure this parameter only affects my servlet and not any others. I also don't want to locate it within my .war file so that I can keep this parameter independent of the applications (for instance if I install an upgrade).
Update: I figured it out, key/value parameters accessible by ServletContext.getInitParameter() go here (or can go here) in ${CATALINA_HOME}/conf/server.xml:
<Server port=... >
...
<Service name="Catalina" ...>
<Engine name="Catalina" ...>
...
<Host name="localhost" ...>
<Context path="/myWarFile">
<Parameter name="foo" value="123" />
<Parameter name="bar" value="456" />
...
</Context>
</Host>
</Engine>
</Service>
</Server>
This sets two parameters, "foo" = "123", "bar" = "456" for the servlet myWarFile.war (or more accurately with the URL path /myWarFile) and I can get at them in Java with Servlet.getServletConfig().getInitParameter("foo") or Servlet.getServletConfig().getInitParameter("bar").
I also looked at JIRA's server.xml entry (and what they tell you to set it to for MySQL), they use a Resource rather than a Parameter, not quite sure of the subtleties of this but it seems like it could be more appropriate method.
<Server port=... >
<Service name="Catalina" ...>
<Engine name="Catalina" ...>
<Host name="localhost" ...>
<Context path="/jira" docBase="${catalina.home}/atlassian-jira"
reloadable="false">
<Resource name="jdbc/JiraDS" auth="Container" type="javax.sql.DataSource"
username="jirauser"
password="..."
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost/jiradb1?autoReconnect=true&useUnicode=true&characterEncoding=UTF8"
maxActive="20"
validationQuery="select 1"
/>
</Context>
</Host>
</Engine>
</Service>
</Server>
you can add the path to your properties files in your CATALINA_HOME/conf/catalina.properties in the "common" classloader common.loader.

Categories

Resources