I have an application running on a tomcat 8 which is working fine. Now I want to build the application for a development, a test and a production environment where the application connects to different database servers and I would like to select which resource to use by a maven property set in the different profiles.
So in my context.xml I have defined my data sources looking like this for each DB server.
<Resource name="jdbc/db-dev" auth="Container"
type="javax.sql.DataSource" maxTotal="1000" maxIdle="30"
maxWaitMillis="10000" username="user" password="password"
driverClassName="org.mariadb.jdbc.Driver"
url="jdbc:mariadb://x.x.x.x:3306/dbname;" />
<Resource name="jdbc/db-test" auth="Container"
type="javax.sql.DataSource" maxTotal="1000" maxIdle="30"
maxWaitMillis="10000" username="user" password="password"
driverClassName="org.mariadb.jdbc.Driver"
url="jdbc:mariadb://x.x.x.x:3306/dbname;" />
And in my web.xml
<resource-ref>
<description>DB Connection</description>
<res-ref-name>${db.context}</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
And in my pom.xml
<profile>
<id>dev</id>
<properties>
<db.context>jdbc/db-dev</db.context>
</properties>
</profile>
And in Java
try {
Context initContext = new InitialContext();
Context envContext = (Context) initContext.lookup(ENV);
DataSource ds = (DataSource) envContext.lookup("jdbc/db"); // jdbc/db-??? is the issue
return ds.getConnection();
} catch (NamingException e) {
throw new SQLException(e);
}
And there's the problem, in Java I have a fixed string value pointing to only one resource. I know I could create a properties file during build, but for only that one value it seems a little to much. Is there a way to have the resource-ref point to different resources from the context xml while having only one reference name?
Another method I found was to have different resource files which I can include and exclude probably per profile, haven't got into it that much yet but maybe there is a far more easy solution which I just don't see right now.
I would prefer to have the same binaries (i.e. WAR in this case) for every environments in order to follow "Build one, deploy often" CI/CD principle. The environment dependent configurations will then be injected in some ways such as through environment variables ,JVM options when starting the application or external configuration file etc.
From this , Tomcat supports using ${xxxx} for variable substitution in their configuration file :
Tomcat configuration files are formatted as schemaless XML; elements
and attributes are case-sensitive. Apache Ant-style variable
substitution is supported; a system property with the name propname
may be used in a configuration file using the syntax ${propname}. All
system properties are available including those set using the -D
syntax, those automatically made available by the JVM and those
configured in the $CATALINA_BASE/conf/catalina.properties file.
So, context.xml will probably looks likes:
<Resource name="jdbc/db" auth="Container"
type="javax.sql.DataSource" maxTotal="1000" maxIdle="30"
maxWaitMillis="10000" username="${DB_USER}" password="${DB_PASSWORD}"
driverClassName="org.mariadb.jdbc.Driver"
url="jdbc:mariadb://${DB_HOST}/dbname;" />
Then configure ${DB_USER} , ${DB_PASSWORD} and ${DB_HOST} as an environment variables or JVM options when starting tomcat etc....
I've been fighting with this for a while now... I built a new server and am upgrading an app for current versions. Works fine now in Eclipse. But I can't get the new server right.
Using Tomcat 8.5.8, Ubuntu 16.04 server, OpenJDK 1.8.0_111, mysql-connector-5.1.40, mysql-server 5.7
I'm using the generic Tomcat downloaded in /opt/tomcat and the mysql-connector-java.jar is in /opt/tomcat/lib - and not in the app's lib. Works as a server just fine but I can't seem to connect to the database. However, in Eclipse it does on my dev box.
I have updated the Context resource as per the new Tomcat 8 docs. See below - taken mostly from the docs. At least it's not the same as what I had for Tomcat 7. That generated tons of warnings.
I understand the DBCP implementation changed. And I am pretty sure I am using the new one. I suspect I have the wrong version of a jar somewhere. But it should be pretty vanilla as it's a clean install.
Previously I tried offical Ubuntu Tomcat 8 as installed by apt. But that did the same thing. And had many more strange warnings due to the package seemingly missing stuff.
Any help will be most appreciated.
What I get is this:
24-Nov-2016 16:14:36.870 SEVERE [http-nio-8080-exec-1] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [jsp] in context with path [] threw exception [javax.servlet.ServletException: javax.servlet.jsp.JspException: Unable to get connection, DataSource invalid: "java.lang.NullPointerException"] with root cause
javax.servlet.jsp.JspException: Unable to get connection, DataSource invalid: "java.lang.NullPointerException"
at org.apache.taglibs.standard.tag.common.sql.QueryTagSupport.getConnection(QueryTagSupport.java:285)
at org.apache.taglibs.standard.tag.common.sql.QueryTagSupport.doStartTag(QueryTagSupport.java:168)
at org.apache.jsp.index_jsp._jspx_meth_sql_005fquery_005f0(index_jsp.java:269)
at org.apache.jsp.index_jsp._jspx_meth_c_005fif_005f0(index_jsp.java:231)
at org.apache.jsp.index_jsp._jspService(index_jsp.java:159)
Based on this:
<Context docBase="app" path="/" reloadable="true" crossContext="true">
<Resource name="jdbc/appdb" username="root" password="password"
url="jdbc:mysql://127.0.0.1:3306/app?autoReconnect=true&zeroDateTimeBehavior=convertToNull&jdbcCompliantTruncation=false&useOldAliasMetadataBehavior=true&useSSL=false"
auth="Container"
type="javax.sql.DataSource"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
testWhileIdle="true"
testOnBorrow="true"
testOnReturn="false"
validationQuery="SELECT 1"
validationInterval="30000"
timeBetweenEvictionRunsMillis="30000"
maxActive="100"
minIdle="10"
maxWait="10000"
initialSize="10"
removeAbandonedTimeout="60"
removeAbandoned="true"
logAbandoned="true"
minEvictableIdleTimeMillis="60000"
jmxEnabled="true"
jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;
org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"
driverClassName="com.mysql.jdbc.Driver"
/>
</Context>
I'm having a similar issue here:
Configuring jdbcRealm in context.xml
Example configuration - My realm is nested in the context because I want it to be specific to the web application.
<Context>
<Realm className="org.apache.catalina.realm.JDBCRealm" debug="9"
connectionName="username"
connectionPassword="password"
connectionURL="url"
driverName="com.ibm.db2.jcc.DB2Driver"
roleNameCol="PERMISSION"
userCredCol="PASSWORD"
userNameCol="USERID"
userRoleTable="ROLESTABLE"
userTable="USERSTABLE"/>
</Context>
The solution was to put the driver jar into tomcat/lib folder. If I put the db2 driver jar in that folder it works.
However, I would like to load the jar from the application/WEB-INF/lib so that I don't have to make changes to the Tomcat installation. The jar is there, but the authenticator can't seem to locate it.
Thanks!
After tinkering around, I found a solution. The DB is resourced and the realm references that resource instead of specifying the JDBCRealm itself. The following context.xml goes in the META-INF folder of the web app.
<Context>
<Resource name="jdbc/DBNAME"
auth="Container"
type="javax.sql.DataSource"
factory="org.apache.commons.dbcp.BasicDataSourceFactory"
maxActive="25"
maxWait="30000"
username="USERNAME"
password="PASSWORD"
driverClassName="DRIVER"
url="URL"
removeAbandoned="true"
logAbandoned="true"
validationQuery="select * from test"
testOnBorrow="true"
testWhileIdle="true"
timeBetweenEvictionRunsMillis="1800000"
/>
<Realm className="org.apache.catalina.realm.DataSourceRealm"
dataSourceName="jdbc/DBNAME"
localDataSource="true"
roleNameCol="PERMISSION"
userCredCol="PASSWORD"
userNameCol="USERID"
userRoleTable="ROLESTABLE"
userTable="USERSTABLE"/>
</Context>
Thanks!
i used tomcat 7 and netbeans 7.4
when i start my web application i get
Cannot deploy the module. The context.xml file seems to be broken. Check whether it is well-formed and valid.
The module has not been deployed.
it's my context.xml file
<?xml version='1.0' encoding='utf-8'?>
<Context>
<Resource name="jdbc/shareDS" auth="Container" type="javax.sql.DataSource"
maxActive="50" maxIdle="10" maxWait="100000"
username="${db.user}" password="${db.password}" driverClassName="com.mysql.jdbc.Driver"
url="${db.url}"
timeBetweenEvictionRunsMillis="1800000" autoReconnect="true"
removeAbandoned="true" removeAbandonedTimeout="300" logAbandoned="true"/>
</Context>
when i try to validate my context file, i get
Cannot find the declaration of element 'Context'. [19]
any idea?
Figured it out. The Netbeans deployment process wants you to add 1 simple parameter to the Context tag, namely: path. It needs to know what path the application will be on.
For example, this was my (opening) Context tag:
<Context antiJARLocking="true" path="/sas/">
My application is deployed at the /sas/ context root.
And now, Netbeans deploys my application without any further errors.
FYI: the antiJARLocking is something I put in to avoid locking of JAR's. It's not mandatory.
For more information on the antiJARLocking, refer to the documentation over at: http://tomcat.apache.org/tomcat-7.0-doc/config/context.html
I deploy a application to tomcat with context xml. I want the tomcat work at debug mode, I means if I change something inside a function, like change
String a="123";
to
String a="456";
tomcat should get the change without reload the application.
The web01.xml under %CATALINA_HOME%/conf/Catalina/localhost
<?xml version='1.0' encoding='utf-8'?>
<Context docBase="d:/document/workspace3.6/web01/WebContent" path="/web01" reloadable="false" debug="1" ></Context>
but now tomcat didn't worked as I expected, if I replace the old class file with new version, I must restart tomcat to get the change.
Why tomcat didn't reload the class,How should I do to let it work as debug mode?
I am not use Eclipse now. and I don't want to set reloadable="true", this will reload the entire application if class changed.
I used tomcat5.5.23
You're actually confusing the notions of "debugging" and hot deploy. You can configure Tomcat for debug mode, and then remotely debug your application running inside tomcat such that when you add a break point in your code, the debugger will jump to that breakpoint and halt execution.
What you actually need there is having the possibility to hotdeploy an application. With tomcat, if you modify the .java files and then copy them to the working directory of tomcat, you'll get exactly what you want, namely the ability to change something in a class and have the running tomcat-deployed application take it into account without redeploying the whole application. You can automatize this by configuring your tomcat application context (either in the tomcat server.xml file or in a project specific context.xml file) for your application to have as working directory the directory where your project code gets compiled.
here's an actual example:
Let's say you have a maven project in the directory c:\myProject. You'd have source files in the c:\myProject\src, and then when compiling it you'd get the war file and an exploded directory of the war file content in the c:\myProject\target\myProject.war and respectively c:\myProject\target\myProject. Now, if you configure your tomcat such that for the myProject tomcat context, youd have the working directory configured as c:\myProject\target\myProject, then each time you modify a .java file, the .class corresponding file will be updated in the target (and now also working) dir, and tomcat will take it into account.
I've actually used such a setup to develop with tomcat, but it's not the best. First off tomcat will hotdeploy only certain modifications, such as when you modify something in the body of an existing method. Other modifications will not be taken into account, such as adding a new method - for this you have to do a full redeploy to have it taken into account.
A far better solution is to use maven with the maven jetty plugin. This thing really works as you want: any modification you do to a class of jsp file will me immediately taken into account, and visible in the running app inside jetty.
Ok, here's an actual example:
I have the cnas-war maven project. Once I build it with Maven, I get the following directory:
c:/_andrei/work/cnas/cnas-war/target\cnas-war-0.0.1-SNAPSHOT
In here I have all the stuff that normally would get packaged in the .war file, like .class files, .jsp files, .jar files etc. Effectively it's the .war file exploded.
I also have a Tomcat 5.5 specifically tailored for the deployment of this war, cleverly placed in the tomcat_cnas folder. In the Tomcat config file (conf\server.xml) I have the following:
<?xml version="1.0" encoding="utf-8"?>
<!-- Example Server Configuration File -->
<!-- Note that component elements are nested corresponding to their
parent-child relationships with each other -->
<!-- A "Server" is a singleton element that represents the entire JVM,
which may contain one or more "Service" instances. The Server
listens for a shutdown command on the indicated port.
Note: A "Server" is not itself a "Container", so you may not
define subcomponents such as "Valves" or "Loggers" at this level.
-->
<Server port="8125" shutdown="SHUTDOWN">
<!-- Comment these entries out to disable JMX MBeans support used for the
administration web application
<Listener className="org.apache.catalina.core.AprLifecycleListener" />
<Listener className="org.apache.catalina.storeconfig.StoreConfigLifecycleListener"/> -->
<Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<!-- Global JNDI resources -->
<GlobalNamingResources>
<!-- Test entry for demonstration purposes -->
<Environment name="simpleValue" type="java.lang.Integer"
value="30" />
<Resource auth="Container"
configurationDirectory="c:/cnas-content"
factory="com.genia.toolbox.web.jndi_config.StringContainerFactory"
name="string/activitymanagerConfigurationContainer"
type="com.genia.toolbox.web.jndi_config.StringContainer" />
<Resource name="string/activitymanagerConfigurationContainer"
auth="Container"
type="com.genia.toolbox.web.jndi_config.StringContainer"
factory="com.genia.toolbox.web.jndi_config.StringContainerFactory"
configurationDirectory="c:/cnas-content" />
</GlobalNamingResources>
<!-- Define the Tomcat Stand-Alone Service -->
<Service name="Catalina">
<!-- Define a non-SSL HTTP/1.1 Connector on port 8080 -->
<Connector acceptCount="100" connectionTimeout="20000"
disableUploadTimeout="true" enableLookups="false"
maxHttpHeaderSize="8192" maxSpareThreads="75" maxThreads="150"
minSpareThreads="25" port="8081" redirectPort="8443" />
<!-- Define the top level container in our container hierarchy -->
<Engine defaultHost="localhost" name="Catalina">
<!-- for activitymanager -->
<Host name="localhost" appBase="webapps" unpackWARs="true"
autoDeploy="true" xmlValidation="false"
xmlNamespaceAware="false">
<Context path="/cnas"
docBase="c:/_andrei/work/cnas/cnas-war/target/cnas-war-0.0.1-SNAPSHOT/"
workDir="c:/_andrei/work/cnas/cnas-war/target/work-cnas/">
<ResourceLink name="string/configurationContainer"
global="string/activitymanagerConfigurationContainer"
type="com.genia.toolbox.web.jndi_config.StringContainer" />
<Resource name="bean/cnasConfig" auth="Container"
type="com.genia.toolbox.projects.cnas.war.config.CnasConfig"
factory="org.apache.naming.factory.BeanFactory"
classpath="false" fileSystem="true"
applicationFileLocation="c:/cnas-content/application.properties" />
<Resource name="bean/cnasApplicationData"
auth="Container"
type="com.genia.toolbox.projects.cnas.war.config.CnasConfig"
factory="org.apache.naming.factory.BeanFactory"
classpath="false" fileSystem="true"
applicationFileLocation="c:/cnas-content/cnas_application_data.xml" />
</Context>
<!--Context docBase="C:/travail/workspace/cnas/cnas-ws-proxy/target/webapp" path="/proxy">
<Resource name="bean/params"
auth="Container"
type="fr.genia.cnas.config.Parameters"
factory="org.apache.naming.factory.BeanFactory"
log4jFile=""
serviceUrl=""
debugMode="true" >
</Resource>
</Context-->
</Host>
</Engine>
</Service>
</Server>
As you can see, in the "context" tag I have a docBase property pointing to the snapshot directory (the one where the war is exploded after maven builds it). Now, with this setup, and having this project imported into Eclipse, if I do a maven build, and then start this Tomcat, the war will be deployed and running. At this point, if I modify the content of a method in a .java file inside Eclipse (and save), then that code will be automatically taken into account by Tomcat and the application will behave differently, without any extra re-deployment. Hope this helps
How to configure Tomcat 5.5 for debug mode?
To do what you are trying to do, You would need some thing like java rebel or some thing similar I know there are some open source alternatives to do the same.