Configure DBCP inside of Tomcat - tomcat7

I am trying to inject DataSource into Servlet. Finally I've annotated datasource field with #Resource and some DBCP's BasicDataSource was injected there. But it has no configuration. No db url, no driver class, nothing. Naturally I got NullPointerException when trying to getConnection(). What am I doing wrong?
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<servlet>
<servlet-name>testServlet</servlet-name>
<servlet-class>ua.test.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>testServlet</servlet-name>
<url-pattern>/serve</url-pattern>
</servlet-mapping>
<resource-ref>
<res-ref-name>jdbc/MyDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<injection-target>
<injection-target-class>ua.test.TestServlet</injection-target-class>
<injection-target-name>dataSource</injection-target-name>
</injection-target>
</resource-ref>
</web-app>
context.xml
<?xml version='1.0' encoding='utf-8'?>
<Context>
<Resource name="jdbc/MyDB" auth="Container" type="javax.sql.DataSource"
maxActive="10" maxIdle="30" maxWait="10000"
username="tomcat" password="tomcat" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/test"/>
</Context>

Obviously no one gave a sh*t about my sorrow. So I will answer myself.
Tomcat has it's own(probably modified) copy of Apache Commons DBCP under package org.apache.tomcat.jdbc, but also for some stupid reason includes original DBCP under org.apache.commons.dbcp package. What happens when I try to inject Datasource with #Resource annotation is Tomcat instanting Datasource from original package and injecting this instance to my field. To make Tomcat to use his own copy of DBCP I had to modify my context.xml as follows:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource name="jdbc/MyDB"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
auth="Container" type="javax.sql.DataSource"
maxActive="10" maxIdle="30" maxWait="10000"
username="tomcat" password="tomcat"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/test"/>
</Context>
Basicaly I just added this line:
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
Thanks to everyone who knew the reason but ignored this question for so long time :-)

Related

Failed to look up JNDI DataSource In Spring Boot Application

I have done the bellow mentioned configuration for JNDI DataSource connection for Spring Boot Application that uses an external tomcat.
Tomcat's server.xml configuration like
<GlobalNamingResources>
<!-- Editable user database that can also be used by
UserDatabaseRealm to authenticate users
-->
<Resource name="jdbc/MyPostgresDB"
global="jdbc/MyPostgresDB"
auth="Container"
type="javax.sql.DataSource"
driverClassName="org.postgresql.Driver"
url="jdbc:postgresql://localhost:5432/postgres"
username="postgres"
password="postgres"
maxActive="100"
maxIdle="20"
minIdle="5"
maxWait="10000"/>
Context.xml like
<Context>
<!-- Default set of monitored resources -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<ResourceLink name="jdbc/MyPostgresDB"
global="jdbc/MyPostgresDB”
auth="Container"
type="javax.sql.DataSource" />
Defined the application.properties for spring boot in right way like
spring.datasource.jndi-name=java:comp/env/jdbc/MyPostgres
Updated the web.xml like
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="3.1" 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">
<resource-ref>
<description>JNDI LookUp</description>
<res-ref-name>jdbc/MyPostgresDB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
<!-- <res-sharing-scope>Shareable</res-sharing-scope> -->
</resource-ref>
</web-app>
Still getting the exception like
org.springframework.jdbc.datasource.lookup.DataSourceLookupFailureException:
Failed to look up JNDI DataSource with name
'java:comp/env/jdbc/MyPostgres'
(Full Stacktrace not given as every where it is given)
So what is the solution or why I am getting this exception.
Don't come with the idea of embedded tomcat server for spring boot.
Please help me.
Should be
spring.datasource.jndi-name=java:comp/env/jdbc/MyPostgresDB
from what you wrote above in your definitions.
we should add factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" in Resource tag of server.xml and make sure to set JndiDatasource in the class where you extends SpringBootServletInitializer class
For elaborate answer please refer here

HibernatePersistence javax.naming.NameNotFoundException thrown with DataSource

I am building a Tomcat Servlet application using Hibernate with a jta data source. My persistence.xml has the following content:
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="metadata.model" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>jdbc/BitronixJTADataSource</jta-data-source>
...
</persistence>
In my ${web-app}/WebContent/META-INF/Context.xml, I have the following content:
<Context>
<Resource name="jdbc/BitronixJTADataSource" auth="Container"
type="javax.sql.DataSource"
maxActive="100" maxIdle="30" maxWait="10000"
username="root" password="mysecretpassword"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/metadatadb" />
</Context>
Right after the application is started, I issue:
emf = Persistence.createEntityManagerFactory("metadata.model");
entityManager = emf.createEntityManager();
and get a
javax.naming.NameNotFoundException: Name [jdbc/BitronixJTADataSource] is not bound in this Context. Unable to find [jdbc].
Do you have any idea why this is occuring?
It appears that in the persistence.xml, the jta-data-source was supposed to have the java:comp/env/jdbc/BitronixJTADataSource value in order for it to be found in the InitialContext.

How to set publishedUrl of a CXF service used by its WS-Discovery plugins?

I am trying to publish the URL of a CXF service using the CXF WS-Discovery plugins.
The tutorial https://cxf.apache.org/docs/writing-a-service-with-spring.html helps me to build an helloworld service.
The CXF documentation of WS-Discovery https://cxf.apache.org/docs/ws-discovery.html, explain that adding cxf-services-ws-discovery-service.jar allow to publish it.
Great, but the published url is relative to the servlet and then not reachable from client that send the WS-Discovery Probe.
I found an interesting approach http://osdir.com/ml/users-cxf-apache/2012-05/msg00524.html that suggests to use the following web.xml and cxf-servlet.xml files :
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app.xsd">
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/webservices/*</url-pattern>
</servlet-mapping>
</web-app>
cxf-servlet.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<bean id="localhost" class="java.net.InetAddress" factory-method="getLocalHost" />
<bean id="publishedWebServiceUrl" class="java.lang.String">
<constructor-arg value="#{'http://' + localhost.hostAddress + ':8080' + servletContext.contextPath + '/webservices/hello_world'}"/>
</bean>
<jaxws:endpoint id="hello_world" implementor="HelloWorldImpl" address="/hello_world">
<jaxws:properties>
<entry key="publishedEndpointUrl" ><ref bean="publishedWebServiceUrl" /></entry>
</jaxws:properties>
</jaxws:endpoint>
</beans>
This works fine if the servlet container use the port 8080.
I tried to use servletContext.getRealPath('/webservices') but this give the filesystem path and not the http address.
Is there a way to get the servlet container port (compliant with tomcat, jetty, ...) ? or an other way to publish an exportable URL ?
I'm afraid you need configure the address from outside, I don't think CXF can tell the port that the servlet container is using.

Picking up Tomcat's Context.xml parameters via SpEL

Deploying war to Apache Tomcat 8 the following way.
Placing myApp.xml under $CATALINA_HOME/conf/[enginename]/[hostname]/
with the following contents:
<Context>
<Parameter name="myApp_configs" value="file:/the/path/to/configs/folder"
type="java.lang.String" override="false"/>
</Context>
B.t.w. I do not place any kind of Context.xml into war.
Then copying myApp.war to $CATALINA_HOME/webapps
This is my web.xml
<?xml version="1.0" encoding="UTF-8"?>
<!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>
<display-name>service</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/beans.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<display-name>CXF Servlet</display-name>
<servlet-class>
org.apache.cxf.transport.servlet.CXFServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
And this way I try loading properties-file in beans.xml (referenced in web.xml above).
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">
<!-- Imported resources for cxf -->
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<!--context:property-placeholder
location="#{contextParameters['myApp_configs']}/myApp.properties"/-->
<bean id="configurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location"
value="#{contextParameters['myApp_configs']}/myApp.properties"/>
</bean>
...other lines follow here...
</beans>
However I am getting following error upon beans loading:
Field or property 'contextParameters' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext'
Could you help me understand the error and propose a fix so that I can access Context-defined parameters?
P.S. I have not put here, but I also have some <Environment>-nodes in Context, and they are successfully accessible via JNDI in other places.
So as we were not able to solve the root cause - why contextParameters bean is not available, the following workaround (using ol' syntax) took place:
<bean id="myConfigsLocation"
class="org.springframework.web.context.support.ServletContextParameterFactoryBean">
<property name="initParamName" value="myApp_configs" />
</bean>
<context:property-placeholder
location="#{myConfigsLocation}/myApp.properties" />
And it worked successfully.

JNDI spring embedded tomcat : maven multi module project

I still cant get this thing in my head :
this is how my project looks :
--app
--app-core (spring)
--app-model (pojo)
--app-service (jersey) >> final package as war (dependencies (appcore+appmodel))
Now here where should my applicationContext.xml sits ????
Dependencies of Spring goes to only app-core ???? ...
UPDATE
app-core (spring) has applicationContext.xml, Know I would like to use JNDI with embedded tomcat (tomcat-maven-plugin).
Have created context.xml inside webapp/META-INF it looks like :-
<?xml version='1.0' encoding='utf-8'?>
<Context docBase="nweb" path="/nweb" reloadable="true">
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<Resource name="jdbc/TestDS" auth="Container"
type="javax.sql.DataSource"
driverClass="net.sourceforge.jtds.jdbc.Driver"
url="jdbc:sqlserver://localhost:1433;DatabaseName=TestData"
username="sa" password=""/>
</Context>
..
my applicationContext.xml : -
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:/TestDS"></property>
</bean>
</beans>
with the above I get this below error :
at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:352)
Caused by: javax.naming.NameNotFoundException: Name TestDSis not bound in this
Context
at org.apache.naming.NamingContext.lookup(NamingContext.java:770)
at org.apache.naming.NamingContext.lookup(NamingContext.java:153)
at org.apache.naming.SelectorContext.lookup(SelectorContext.java:152)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
at org.springframework.jndi.JndiTemplate$1.doInContext(JndiTemplate.java:154)
at org.springframework.jndi.JndiTemplate.execute(JndiTemplate.java:87)
at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:152)
at org.springframework.jndi.JndiTemplate.lookup(JndiTemplate.java:178)
at org.springframework.jndi.JndiLocatorSupport.lookup(JndiLocatorSupport.java:95)
at org.springframework.jndi.JndiObjectLocator.lookup(JndiObjectLocator.java:105)
at
Any suggestions if am missing out anything ?
Typically you would configure a ContextLoaderListener on your web.xml for your root application context:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
This class uses the param value contextConfigLocation -- from which you can explicitly specify where your applicationContext.xml should be:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/spring/applicationContext*.xml</param-value>
</context-param>
try
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
<contextFile>webapp/META-INF/context.xml</contextFile>
</configuration>
</plugin>
try <property name="jndiName" value="java:comp/env/TestDS"></property>
if you are using embedded tomcat 7 then you should call
tomcat.enableNaming();
You have an application working with JNDI here. I have been using JNDI on a PaaS where they explain how to do the binding between your app and the db. You can have more details on this tutorial.
Basically you need to put this on your datasource.xml file:
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/mydb" resource-ref="true"
expected-type="javax.sql.DataSource"/>
Then, on your Tomcat server, you have several possibilities as you can see on the Spring tutorial I put the link. Easiest way is going to $CATALINA_HOME/conf/context.xml and put something like this.
<Resource auth="Container" driverClassName="com.mysql.jdbc.Driver" factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" maxActive="20" maxIdle="10" minIdle="1" name="jdbc/mydb" password="dbUserPassword" testOnBorrow="true" testWhileIdle="true" type="javax.sql.DataSource" url="jdbc:mysql://localhost:3306/dbName" username="dbUserName" validationInterval="5000" validationQuery="select 1"/>

Resources