Tomcat 8 - Virtual Host Not Recompiling JSPs or Recognizing Updated Classes - java

I've just unpacked and configured Tomcat 8.0.3 on Windows 7 with a virtual host. I've tested it successfully under the default webapps, however, my virtual host is not recognizing changes in JSP files or classes.
Here is my set up:
%CATALINA_HOME%\conf\server.xml
...
<Engine name="Catalina" defaultHost="localhost">
...
<Host name="ww.virtual.com" appBase="vapps" unpackWARs="true" autoDeploy="true">
</Host>
</Engine>
...
%SystemRoot%\system32\drivers\etc\hosts
...
127.0.0.1 ww.virtual.com
%CATALINA_HOME%\vapps\ROOT\META-INF\context.xml
<?xml version="1.0" encoding="UTF-8"?>
<Context antiResourceLocking="true" privileged="true" reloadable="true">
<Resource name="jdbc/INVENTORY" auth="Container" type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="sqlusr" password="secret1" driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
url="jdbc:sqlserver://127.0.0.1:1433;instanceName=SQLSERVER;DatabaseName=INVENTORY"/>
</Context>
%CATALINA_HOME%\vapps\ROOT\WEB-INF\web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1"
metadata-complete="true">
<display-name>Test Display</display-name>
<description>Test Description</description>
<resource-ref>
<description>Test DB Connection</description>
<res-ref-name>jdbc/INVENTORY</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>
I then have JSP files located in %CATALINA_HOME%\vapps\ROOT\ and classes in %CATALINA_HOME%\vapps\ROOT\WEB-INF\classes\MainPackage\ which are properly loaded when the server is started. But if I make any changes to the JSPs or .class files, the server does not recognize the update. What am I doing wrong?

This is happening because you have enabled anti-resource locking. With that option enable the web application is not deployed from the appBase but from a copy in the work directory. If you edit the copy in the work directory you'll see the changes.
Alternatively, remove the anti-resource locking options and fix whatever bug caused you to need them in the first place.

Related

How to define default context elements with Tomcat?

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.

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.

Datasource JNDI configuration in Tomcat 7.0 for Hibernate

When Datasource is configured in (tomcat 7) server.xml or in Context.xml, hibernate is not able to identify JNDI and throwing below excpetion but same is working fine when I tried to access datasource using JNDI in the code. What am doing wrong
Below is my configuration in hibernate.properties
hibernate.connection.driver_class com.mysql.jdbc.Driver
hibernate.connection.pool_size 10
hibernate.dialect org.hibernate.dialect.MySQL5Dialect
hibernate.connection.datasource java:comp/env/jdbc/employee
hibernate.show_sql true
hibernate.format_sql true
in server.xml
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<!-- SingleSignOn valve, share authentication between web applications
Documentation at: /docs/config/valve.html -->
<!--
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
-->
<!-- Access log processes all example.
Documentation at: /docs/config/valve.html
Note: The pattern used is equivalent to using pattern="common" -->
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log." suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" resolveHosts="false"/>
**<Context docBase="hibernate" path="/hibernate">
<Resource name="jdbc/employee" auth="Container"
type="javax.sql.DataSource" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:45000/hibernatetest"
username="user" password="hibernate" maxActive="20" maxIdle="10"
maxWait="-1" removeAbandoned="true" removeAbandonedTimeout="60" logAbandoned="true"/>
</Context>**
</Host>
In Context.xml file
**<Context docBase="hibernate" path="/hibernate">
<Resource name="jdbc/employee" auth="Container"
type="javax.sql.DataSource" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:45000/hibernatetest"
username="user" password="hibernate" maxActive="20" maxIdle="10"
maxWait="-1" removeAbandoned="true" removeAbandonedTimeout="60" logAbandoned="true"/>
</Context>**
Finally below is my web.xml file
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
**<web-app >
<servlet>
<servlet-name>employee</servlet-name>
<servlet-class>edu.experiments.web.EmployeViewer</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>employee</servlet-name>
<url-pattern>/employee</url-pattern>
</servlet-mapping>
<resource-ref>
<description>DB Connection</description>
<res-ref-name>jdbc/employee</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>**
org.hibernate.service.jndi.JndiException: Unable to lookup JNDI name [java:comp/env/jdbc/employee]
It is simpler than it may seem:
don't put anything about JNDI in your web.xml
in the context.xml you are using (whether global or webapp relative) use the proper name, say "jdbc/employee"
to hibernate configuration pass the name in the form "java:comp/env/jdbc/employee"
Here is the reference page:
http://tomcat.apache.org/tomcat-7.0-doc/jndi-datasource-examples-howto.html

How can I use Java console app and Hibernate using Tomcat Context?

I have some Java-console-apps. which are using Hibernate to take care some database stuff (I use MySQL). Now, I want Hibernate to use datasource from Tomcat Context. Could anyone tell me how?
Tomcat wiki contains the needed configuration.
in context.xml:
<?xml version="1.0" encoding="UTF-8"?> <Context antiJARLocking="true" path="/DVDStore">
<Resource auth="Container"
driverClassName="com.mysql.jdbc.Driver" maxActive="30" maxIdle="10" maxWait="10000" name="jdbc/sakila" password="*****"
type="javax.sql.DataSource" url="jdbc:mysql://localhost/sakila" username="*****"/>
</Context>
In WEB-INF/web.xml .
<resource-ref>
<description>This is a MySQL database connection</description>
<res-ref-name>jdbc/sakila</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
In hibernate.cfg.xml:
<!-- using container-managed JNDI -->
<propertyname="hibernate.connection.datasource">
java:comp/env/jdbc/sakila
</property>
You can find more in The TomcatHibernate Wiki
Edit:
In case you want to access the context directly, this is the way to do it problematically
ServletContext sc = getServletContext();
String parameterValue = sc.getInitParameter("parameterName");

JNDI binding in JBoss (LiveCycle turnkey)

I am using Adobe LiveCycle ES 2 turnkey project, which runs on JBoss AS 4.2.1.GA. I am having a problem getting a JNDI binding to work in JBoss. It seems eerily similar to an earlier post, problem configure JBoss to work with JNDI, but I certainly have found no solution.
This is my setup. I have a -ds.xml file in place:
C:\Adobe\Adobe LiveCycle ES2\jboss\server\lc_turnkey\deploy\rmb-ds.xml
The contents of that file are as follows:
<datasources>
<local-tx-datasource>
<jndi-name>RMB_DS</jndi-name>
<connection-url>jdbc:sqlserver://localhost\SQLEXPRESS;DatabaseName=rmb</connection-url>
<driver-class>com.microsoft.sqlserver.jdbc.SQLServerDriver</driver-class>
<user-name>sa</user-name>
<password>password</password>
<check-valid-connection-sql>SELECT 1 FROM sysobjects</check-valid-connection-sql>
<!-- corresponding type-mapping in the standardjbosscmp-jdbc.xml (optional) -->
<metadata>
<type-mapping>MS SQLSERVER2000</type-mapping>
</metadata>
</local-tx-datasource>
</datasources>
I have a Java project, whose /RMB/WebContent/WEB-INF/web.xml contains the following:
<resource-ref>
<description>DB Connection</description>
<res-ref-name>java:RMB_DS</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
Now, every time I deploy the WAR, it fails with the following error:
2011-09-06 15:44:17,786 ERROR [org.jboss.deployment.MainDeployer] Could not start deployment: file:/C:/Adobe/Adobe LiveCycle ES2/jboss/server/lc_turnkey/deploy/RMB.war
org.jboss.deployment.DeploymentException: Error during deploy; - nested throwable: (javax.naming.NamingException: resource-ref: java:RMB_DS has no valid JNDI binding. Check the jboss-web/resource-ref.)
at org.jboss.web.AbstractWebDeployer.start(AbstractWebDeployer.java:384)
...
Caused by: javax.naming.NamingException: resource-ref: java:RMB_DS has no valid JNDI binding. Check the jboss-web/resource-ref.
at org.jboss.web.AbstractWebDeployer.linkResourceRefs(AbstractWebDeployer.java:623)
I am 100% positive that the JNDI binding itself is correct. I can see the following in web console > System > JMX Beans > jboss.jdbc > jboss.jdbc:service=metadata,datasource=RMB_DS
MBean Name: Domain Name: jboss.jdbc
service: metadata
datasource: RMB_DS
MBean Java Class: org.jboss.ejb.plugins.cmp.jdbc.metadata.DataSourceMetaData
Also, using LiveCycle workbench I can make a process that hits this service and runs some SQL against datasource java:/RMB_DS..
SO, there has to be something wrong with my WAR or web.xml right? Am I missing something obvious?
Thanks to Ketan, who is awesome!
Needed a jboss-web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web>
<resource-ref>
<res-ref-name>RMB_DS</res-ref-name>
<jndi-name>java:/RMB_DS</jndi-name>
</resource-ref>
</jboss-web>
And changed the original web.xml to have:
<resource-ref>
<description>DB Connection</description>
<res-ref-name>RMB_DS</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
Which matches rmb-ds.xml
<datasources>
<local-tx-datasource>
<jndi-name>RMB_DS</jndi-name>
<connection-url>jdbc:sqlserver://localhost\SQLEXPRESS;DatabaseName=RMB</connection-url>
<driver-class>com.microsoft.sqlserver.jdbc.SQLServerDriver</driver-class>
<user-name>sa</user-name>
<password>password</password>
<check-valid-connection-sql>SELECT 1 FROM sysobjects</check-valid-connection-sql>
<!-- corresponding type-mapping in the standardjbosscmp-jdbc.xml (optional) -->
<metadata>
<type-mapping>MS SQLSERVER2000</type-mapping>
</metadata>
</local-tx-datasource>
</datasources>

Categories

Resources