TomEE Embedded: Resource defined in resources.xml not available within webapp - datasource

I'm currently trying to run a simple webapp on TomEE Embedded (TomEE Version 7.0.5).
According to the docs, I can start the TomEE and deploy the classpath as a webapp like this. I've set the document base to src/main/webapp.
try (final Container container = new Container(new Configuration())
.deployClasspathAsWebApp("", new File("src/main/webapp"))) {
container.await();
}
I have defined a datasource in WEB-INF/resources.xml which looks like this:
<Resource id="myDataSource" type="javax.sql.DataSource">
JdbcDriver org.hsqldb.jdbcDriver
JdbcUrl jdbc:hsqldb:file:hsqldb
UserName sa
Password
</Resource>
And I've setup a reference in the web.xml:
<resource-ref>
<res-ref-name>myDataSource</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
</resource-ref>
Then I try to lookup this datasource in my Servlet via JNDI.
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
Context initCtx = new InitialContext();
DataSource ds = (DataSource) initCtx.lookup("java:comp/env/myDataSource");
Connection connection = ds.getConnection();
...
}
When the TomEE starts, it seems like my DataSource is created (at least there is some output about that in the logs). However when I try to lookup the DataSource in my servlet, I get an unconfigured dbcp2 connection pool as a DataSource which throws the following exception when ds.getConnection() is called:
java.sql.SQLException: Cannot create JDBC driver of class '' for connect URL 'null'
at org.apache.tomcat.dbcp.dbcp2.BasicDataSource.createConnectionFactory(BasicDataSource.java:2186)
at org.apache.tomcat.dbcp.dbcp2.BasicDataSource.createDataSource(BasicDataSource.java:2066)
at org.apache.tomcat.dbcp.dbcp2.BasicDataSource.getConnection(BasicDataSource.java:1525)
at TestServlet.doGet(TestServlet.java:32)
...
The same configuration works fine on a standalone TomEE (I tried TomEE Webprofile) or when using the TomEE Maven Plugin. Is there anything I'm missing to get it running also for Embedded TomEE?
Thanks in advance

Tomee embedded does not bind a custom webapp classloader by default so does not have comp/ always bound. You can pass properties to the context to force it to be openejb one or use openejb:Resource/myDataSource or java:openejb/Resource/myDataSource naming.

Related

AbstractMethodError with jTDS JDBC Driver on Tomcat 8

I am deploying a web app (WAR) to a Tomcat 8 web container.
The WAR includes in the '/WEB-INF/lib' directory the following jTDS JDBC driver:
<dependency org="net.sourceforge.jtds" name="jtds" rev="1.3.1" />
(file is: jtds-1.3.1.jar).
This is how the resource is defined in META-INF/context.xml:
<Resource name="jdbc/jtds/sybase/somedb"
auth="Container"
type="javax.sql.DataSource"
driverClassName="net.sourceforge.jtds.jdbc.Driver"
url="jdbc:jtds:sybase://localhost:2501/somedb"
username="someuser" password="somepassword"
/>
In my code I obtain the javax.sql.DataSource the normal way:
InitialContext cxt = new InitialContext();
if ( cxt == null ) {
throw new RuntimeException("Uh oh -- no context!");
}
DataSource ds = (DataSource) cxt.lookup( lookupName );
I further verify (by printing) that the DataSource object ds is of the expected type:
org.apache.tomcat.dbcp.dbcp2.BasicDataSource
… but when I try to get a connection out of it:
Connection conn = ds.getConnection();
… I get the following trace:
java.lang.AbstractMethodError
net.sourceforge.jtds.jdbc.JtdsConnection.isValid(JtdsConnection.java:2833)
org.apache.tomcat.dbcp.dbcp2.DelegatingConnection.isValid(DelegatingConnection.java:924)
org.apache.tomcat.dbcp.dbcp2.PoolableConnection.validate(PoolableConnection.java:282)
org.apache.tomcat.dbcp.dbcp2.PoolableConnectionFactory.validateConnection(PoolableConnectionFactory.java:359)
org.apache.tomcat.dbcp.dbcp2.BasicDataSource.validateConnectionFactory(BasicDataSource.java:2316)
org.apache.tomcat.dbcp.dbcp2.BasicDataSource.createPoolableConnectionFactory(BasicDataSource.java:2299)
org.apache.tomcat.dbcp.dbcp2.BasicDataSource.createDataSource(BasicDataSource.java:2043)
org.apache.tomcat.dbcp.dbcp2.BasicDataSource.getConnection(BasicDataSource.java:1543)
What gives?
Turns out I had to add:
validationQuery="select 1"
in the Resource declaration in context.xml.
This is mentioned here (although mispelled as validateQuery).
Digging into the implementation of JtdsConnection one sees:
/* (non-Javadoc)
* #see java.sql.Connection#isValid(int)
*/
public boolean isValid(int timeout) throws SQLException {
// TODO Auto-generated method stub
throw new AbstractMethodError();
}
This is really weird, I think AbstractMethodError is supposedly thrown by the compiler only, unimplemented methods ought to throw UnsupportedOperationException. At any rate, the following code from PoolableConnection shows why the presence or not of validationQuery in context.xml can change things. Your validationQuery is passed as the value of the sql String parameter in the below method (or null if you don't define a validationQuery):
public void More ...validate(String sql, int timeout) throws SQLException {
...
if (sql == null || sql.length() == 0) {
...
if (!isValid(timeout)) {
throw new SQLException("isValid() returned false");
}
return;
}
...
}
So basically if no validationQuery is present, then the connection's own implementation of isValid is consulted which in the case of JtdsConnection weirdly throws AbstractMethodError.
The answer mentioned above by Marcus worked for me when I encountered this problem. To give a specific example of how the validationQuery setting looks in the context.xml file:
<Resource name="jdbc/myDB" auth="Container" type="javax.sql.DataSource"
driverClassName="net.sourceforge.jtds.jdbc.Driver"
url="jdbc:jtds:sqlserver://SQLSERVER01:1433/mydbname;instance=MYDBINSTANCE"
username="dbuserid" password="dbpassword"
validationQuery="select 1"
/>
The validationQuery setting goes in with each driver setting for your db connections. So each time you add another db entry to your context.xml file, you will need to include this setting with the driver settings.
The above answer works. If you are setting it up for standalone Java application, set the validation query in the datasource.
BasicDataSource ds = new BasicDataSource();
ds.setUsername(user);
ds.setPassword(getPassword());
ds.setUrl(jdbcUrl);
ds.setDriverClassName(driver);
ds.setMaxTotal(10);
ds.setValidationQuery("select 1"); //DBCP throws error without this query

Quartz scheduled jobs could not access datasource in Websphere

I am developing a web app where batch programs need to run for specific times. I used Quartz library to schedule the jobs. The web app is deployed on Websphere 8.5.5 and its working fine, accessing the tables through datasources (Datasource given in code is java:comp/env/jdbc/db_datasource). The job is also triggered at the mentioned times.
I am getting an error when the scheduled job makes a DB connection through the datasource and the error is:
javax.naming.ConfigurationException: A JNDI operation on a "java:" name cannot be completed because the server runtime is not able to associate the operation's thread with any J2EE application component. This condition can occur when the JNDI client using the "java:" name is not executed on the thread of a server application request. Make sure that a J2EE application does not execute JNDI operations on "java:" names within static code blocks or in threads created by that J2EE application. Such code does not necessarily run on the thread of a server application request and therefore is not supported by JNDI operations on "java:" names. [Root exception is javax.naming.NameNotFoundException: Name comp/env/jdbc not found in context "java:".]
at com.ibm.ws.naming.java.javaURLContextImpl.throwExceptionIfDefaultJavaNS(javaURLContextImpl.java:522)
at com.ibm.ws.naming.java.javaURLContextImpl.throwConfigurationExceptionWithDefaultJavaNS(javaURLContextImpl.java:552)
at com.ibm.ws.naming.java.javaURLContextImpl.lookupExt(javaURLContextImpl.java:481)
at com.ibm.ws.naming.java.javaURLContextRoot.lookupExt(javaURLContextRoot.java:485)
at com.ibm.ws.naming.java.javaURLContextRoot.lookup(javaURLContextRoot.java:370)
I understand from the error message is that the job is running outside the J2ee container and so the datasource is not available for the Job to make the connection, which I cannot agree as the Quartz is implemented as the ServletContextListener and the same is mentioned in web.xml.
Web.xml
<listener>
<listener-class>com.ehacampaign.helper.EHAJobSchedulerListener</listener-class>
</listener>
EHAJobSchedulerListener.java
public class EHAJobSchedulerListener implements ServletContextListener {..}
As you can see the code, the class is registered in the web and I do not understand why it cannot use the datasource in the J2EE container.
Questions are:
Why servlet registered class cannot access the datasource in J2EE
container?
If datasource in container cannot be used, then how to make a
connection to the DB while executing the job?
NOTE: I have the same setup in JBoss AS 7.1 and the jobs are running smoothly accessing the datasource configured in JBoss AS 7.1. I have to develop this in Websphere as the customer demands it.
UPDATED
I have attached the modified quartz property file. Even after adding the workmanagerthread, I am getting the same error.
org.quartz.threadPool.threadCount=1
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore
org.quartz.threadExecutor.class=org.quartz.commonj.WorkManagerThreadExecutor
org.quartz.threadExecutor.workManagerName=wm/default
In order to perform JNDI lookups in WebSpehre, your code must be running on a managed thread. In order to have Quartz run on one of WebSphere's managed threads, you must set the following 2 properties in your quartz.properties (as Alasdair mentioned in the comments):
org.quartz.threadExecutor.class=org.quartz.commonj.WorkManagerThreadExecutor
org.quartz.threadExecutor.workManagerName=wm/default
The name for org.quartz.threadExecutor.workManagerName can be the JNDI name of any Work Manager that you have configured in WebSphere. I recommend simply using wm/default because it is in your configuration by default.
With all the help provided by aguibert and Alasdair and reference from here, I am able to fix the issue.
The Quartz property file is:
org.quartz.threadPool.threadCount=1
org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore
org.quartz.threadExecutor.class=org.quartz.commonj.WorkManagerThreadExecutor
org.quartz.threadExecutor.workManagerName=wm/default
The database connection or JNDI lookup should happen within the empty constructor of the JOB Implemented class. For ex,
public class ContractIdFromPartyServiceJob implements Job {
private DataSource ds;
public ContractIdFromPartyServiceJob() {
try {
Logger.info("Gets the data source");
Context context = new InitialContext();
ds = (DataSource) context.lookup(ApplicationConstants.RESOURCE_REFERENCE_JDBC);
} catch (RException e) {
e.printStackTrace();
}
}
#Override
public void execute(JobExecutionContext arg0) throws JobExecutionException
{
EHAMarsDAO marsDao = new EHAMarsDAO();
Connection con = getConnection();
try {
marsDao.callDBMethod(con);
} finally {
con.close();
}
}
public Connection getConnection() throws RACVException
{
Connection con = null;
try {
con = ds.getConnection();
con.setAutoCommit(false);
con.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
} catch (SQLException e) {
throw new RException(Constants.ERROR_CODE_002, Constants.E012_DB_CONNECTION_ERROR, e);
}
return con;
}
}

Spring boot JNDI datasource lookup failure - Name comp/env/jdbc not found in context "java:"

I have setup a spring boot (v 1.1.9) application to deploy as a WAR file. And I'm trying to integrate this web application with an existing data service module (added as a maven dependency).
Environment trying to deploy: WebSphere Application Server 8.5.5.4
The issue I'm facing is an application start-up failure when try to look-up a JNDI dataSource (jdbc/fileUploadDS) as below within the dependent data service module.
#Configuration
#Profile("prod")
public class JndiDataConfig implements DataConfig {
#Bean
public DataSource dataSource() throws NamingException {
Context ctx = new InitialContext();
return (DataSource) ctx.lookup("java:comp/env/jdbc/fileUploadDS");
}
}
My Spring Boot configuration:
#Configuration
#ComponentScan(basePackages = { "au.com.aiaa.fileupload.data.*", "demo" })
#EnableAutoConfiguration(exclude = { HibernateJpaAutoConfiguration.class, DataSourceAutoConfiguration.class })
public class SampleApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(applicationClass, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(applicationClass);
}
private static Class<SampleApplication> applicationClass = SampleApplication.class;
#Bean
public static Properties fileUploadJndiProperties() throws NamingException {
JndiObjectFactoryBean jndiFactoryBean = new JndiObjectFactoryBean();
jndiFactoryBean.setJndiName("props/FileUploadProperties");
jndiFactoryBean.setExpectedType(Properties.class);
jndiFactoryBean.setLookupOnStartup(true);
jndiFactoryBean.afterPropertiesSet();
return (Properties) jndiFactoryBean.getObject();
}
}
Note that I'm able to lookup props/FileUploadProperties successfully. But failing to do the same for a datasource.
My doubt is it is trying to load a EmbeddedWebApplicationContext which is not what I want.
The stack trace is:
Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public javax.sql.DataSource au.com.aiaa.fileupload.data.dao.configuration.JndiDataConfig.dataSource() throws javax.naming.NamingException] threw exception; nested exception is **javax.naming.NameNotFoundException: Name comp/env/jdbc not found in context "java:".**
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:301)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1186)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:537)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:706)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:762)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at **org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:109)**
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:142)
at org.springframework.boot.context.web.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:89)
at org.springframework.boot.context.web.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:51)
at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:175)
..................
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public javax.sql.DataSource au.com.aiaa.fileupload.data.dao.configuration.JndiDataConfig.dataSource() throws javax.naming.NamingException] threw exception; nested exception is **javax.naming.NameNotFoundException: Name comp/env/jdbc not found in context "java:".**
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:188)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:586)
... 132 common frames omitted
Caused by: javax.naming.NameNotFoundException: Name comp/env/jdbc not found in context "java:".
at com.ibm.ws.naming.ipbase.NameSpace.getParentCtxInternal(NameSpace.java:1970)
at com.ibm.ws.naming.ipbase.NameSpace.retrieveBinding(NameSpace.java:1377)
at com.ibm.ws.naming.ipbase.NameSpace.lookupInternal(NameSpace.java:1220)
at com.ibm.ws.naming.ipbase.NameSpace.lookup(NameSpace.java:1142)
at com.ibm.ws.naming.urlbase.UrlContextImpl.lookupExt(UrlContextImpl.java:1436)
at com.ibm.ws.naming.java.javaURLContextImpl.lookupExt(javaURLContextImpl.java:477)
at com.ibm.ws.naming.java.javaURLContextRoot.lookupExt(javaURLContextRoot.java:485)
at com.ibm.ws.naming.java.javaURLContextRoot.lookup(javaURLContextRoot.java:370)
at org.apache.aries.jndi.DelegateContext.lookup(DelegateContext.java:161)
at javax.naming.InitialContext.lookup(InitialContext.java:436)
at au.com.aiaa.fileupload.data.dao.configuration.JndiDataConfig.dataSource(JndiDataConfig.java:41)
at au.com.aiaa.fileupload.data.dao.configuration.JndiDataConfig$$EnhancerBySpringCGLIB$$8001dbbe.CGLIB$dataSource$0(<generated>)
at au.com.aiaa.fileupload.data.dao.configuration.JndiDataConfig$$EnhancerBySpringCGLIB$$8001dbbe$$FastClassBySpringCGLIB$$3c9e0518.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:312)
at au.com.aiaa.fileupload.data.dao.configuration.JndiDataConfig$$EnhancerBySpringCGLIB$$8001dbbe.dataSource(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:611)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:166)
What am I missing here? Even when I try to explicitly define the dataSource bean method in SampleApplication.java like below it fails with the same error.
#Bean
public static DataSource dataSource() throws NamingException {
JndiObjectFactoryBean jndiFactoryBean = new JndiObjectFactoryBean();
jndiFactoryBean.setJndiName("java:comp/env/jdbc/fileUploadDS");
jndiFactoryBean.setExpectedType(DataSource.class);
jndiFactoryBean.setLookupOnStartup(true);
jndiFactoryBean.setResourceRef(true);
jndiFactoryBean.afterPropertiesSet();
return (DataSource) jndiFactoryBean.getObject();
}
I referred this and it says we need to set enableNaming() on servlet container? Can I do something similar for non-embedded web application context? Or is it purely a WAS 8.5 issue??
You need to have resource reference with jdbc/fileUploadDS name in your web.xml. And make sure it is bound to actual datasource name during installation or via ibm-web-bnd.xml file.
Definition in web.xml:
<resource-ref>
<description />
<res-ref-name>jdbc/fileUploadDS</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>
If you dont want to use web.xml, then in normal Java EE app you could just add in web component (servlet, filter) the following class annotation:
#Resource(name="jdbc/fileUploadDS", type=javax.sql.DataSource.class, lookup="jdbc/fileUploadDS")
but I'm not Spring-boot expert, so don't know, if it will work or is possible there.
I am able to connect my Spring-Boot application (deployed in Websphere Application Server 9) to WAS datasource.
The following code worked for me, for connecting to DataSource:
#Bean(name = "WASDataSource")
public DataSource WASDataSource() throws Exception {
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
return dataSourceLookup.getDataSource("DSNAME");
}
#Bean(name = "WASDataSourceJdbcTemplate")
public JdbcTemplate jdbcTemplate_WASDS(#Qualifier("WASDataSource")
DataSource dsDB2) {
return new JdbcTemplate(dsDB2);
}
Note: The name of Datasource "DSNAME" is the name which appears on the UI of Websphere console.
You can see that via -> Select Resources > JDBC > Data Sources.
Then I created jdbc template:
#Autowired
#Qualifier("WASDataSourceJdbcTemplate")
private JdbcTemplate db2WASTemplate;`
And running query using the query method works fine :
db2WASTemplate.query()
I did not create any Web.xml or ibm-web-bnd.xml files
I just configured spring boot with my custom datasource as follows:
#Bean
#ConfigurationProperties("spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
and inside the application.properties file I defined all datasource settings as usual
spring.datasource.driver-class-name= ***
spring.datasource.url= ***
spring.datasource.username= ***
spring.datasource.password= ***
spring.datasource.jndi-name=jdbc/myDB
It works nicely with #SpringBootApplication with all other default settings
I am facing the same problem. I don't know how to define tag in spring boot since there is no web.xml file in the spring boot.
So far what I came to know that we have to define it in the application file from where we start our spring application. I think we need to use this method to set the Datasource:
#Bean(destroyMethod="")
#ConfigurationProperties(prefix="datasource.mine")
public DataSource dataSource() throws Exception {
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
return dataSourceLookup.getDataSource("java:jdbc/configurationFile");
}

Exception error in google doc api

I am new to google api. I am trying to create a simple web application (Java EE) to read DocumentListFeed from google doc. My code in the servlet is:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
try
{
DocsService service = new DocsService("Document List Demo");
service.setUserCredentials(NAME, PASSWORD);
response.getWriter().println("helloooooo");
//URL documentListFeedUrl = new URL("http://docs.google.com/feeds/documents/private/full");
URL documentListFeedUrl = new URL("https://docs.google.com/feeds/default/private/full?v=3");
DocumentListFeed feed = service.getFeed(documentListFeedUrl, DocumentListFeed.class);
for(DocumentListEntry entry : feed.getEntries())
{
response.getWriter().println(entry.getTitle().getPlainText());
}
}
catch (Exception e)
{
response.getWriter().println(e);
}
}
But it is showing me the error: java.lang.NoClassDefFoundError: com/google/gdata/client/docs/DocsService
I am using Glassfish server and Ecllipse. And added external jar file: activation.jar, guava-r07.jar, mail.jar, servlet.jar, gdata-client-1.0.jar, gdata-client-meta-1.0.jar, gdata-core-1.0.jar, gdata-media-1.0.jar, gdata-docs-3.0.jar, gdata-docs-meta-3.0.jar.
I have copied this same code to java standard edition and it is working fine. Could please tell me why this thing is not working in Java EE? Is it a problem in GlassFish server?
It just means that the jars are not present in your Glassfish server classpath.
Add all the jars you listed to yuor glassfish server classpath. Since am not an Glassfish expert i cannot help you in adding the jars to your server.
In case of weblogic, you just need to package all the jars in your project APP-INF directory.
Hope it helps.

Try to make a Connection Pool with Tomcat 6

I really am having a nightmare configuring Tomcat to set up a connection pool. I have done a lot of reading of various forums and the documents from Tomcat but am having to ask here as a last resort. This is the first time I have tried to get connections from the container so it's all new to me.
I have been having NameNotFoundException's which only seem to be fixed when I put the context.xml file back from MyApp/META-INF/context.xml to Tomcat 6.0/conf/context.xml, so for some reason it's not seeing the context.xml file in MyApp's META-INF directory. Any ideas?
Now I am getting an SQLNestedException: Cannot create PoolableConnectionFactory (''#'localhost' (using password:YES))
First of all it suprises me that the user is blank because I have specified 'root' in the context.xml. As for not being able to create a PoolableConnectionFactory, I have seen a couple of example context.xml files that had a factory attribute. Do I need this? If so what class should I specify there?
My context.xml is:
<?xml version='1.0' encoding='utf-8'?>
<Context>
<!-- Configure a JDBC DataSource for the user database -->
<Resource name="jdbc/searchdb"
type="javax.sql.DataSource"
auth="Container"
user="root"
password="mypassword"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/search"
maxActive="8"
maxIdle="4"/>
<!-- Default set of monitored resources -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<!--<WatchedResource>META-INF/context.xml</WatchedResource>-->
</Context>
I have seen a context.xml with a WatchedResource elemnt for the META-INF/context.xml. I tried it but it didn't seem to make a difference and it seems strange to me so I have commented it out. Should I actually be including it?
My test servlet:
package search.web;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
import java.sql.*;
import javax.sql.*;
import javax.naming.*;
import search.model.*;
public class ConPoolTest extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
Context ctx = null;
DataSource ds = null;
Connection conn = null;
try {
ctx = new InitialContext();
ds = (DataSource)ctx.lookup("java:comp/env/jdbc/searchdb");
conn = ds.getConnection();
if(conn != null) {
System.out.println("have a connection from the pool");
}
} catch(SQLException e) {
e.printStackTrace();
} catch(NamingException e) {
e.printStackTrace();
} finally {
try {
if(conn!=null) {
conn.close();
}
} catch(SQLException e) {
e.printStackTrace();
}
}
}
}
I look forward to your suggestions.
Many thanks
Joe
PS I would have also listed the stack trace, but for some reason it is showing up in the console, but not in the logs.
Update:
Now that I look at the error message again I'm wondering what it is that is denying me access. I assumed that it was the database, but is itactually the container? Do I need to set up some sort of authentication in the tomcatusers.xml file?
The Tomcat docs for JNDI Datasources contain complete examples how to setup JDBC data sources in the context.xml
Some comments to your question:
Tomcat should copy the context.xml from your app's WAR to conf/Catalina/localhost/app.xml during deployment (when it unpacks your app). The file should not go to conf/. Check whether you have an old copy lying around in these places and clean that up.
The error that it's using the wrong user also suggests that there is more than a single context.xml and you're looking at the wrong one.
You don't need PoolableConnectionFactory with Tomcat 6. This might be cruft left from an update from Tomcat 5 or something broke and they tried several things and forgot to clean up the config file.
Tomcat automatically watches web.xml; there is no need to make it a WatchedResource a second time.