I was wondering how one would go about getting an object from a remote JNDI in Spring 3. Where do you specify the URL, how do you set it all up in a context file, etc. I have found some disperate information suggesting this is possible, but no singular source for how to do it for a JNDi that is on a different server.
You could use, for example, the JndiObjectFactoryBean class within a basic configuration like this one:
<bean id="someId" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="yourLookupNameGoesHere" />
<property name="jndiEnvironment">
<props>
<prop key="java.naming.provider.url">yourRemoteServerGoesHere:PortGoesHere</prop>
<prop key="java.naming.factory.initial">yourNamingContextFactoryGoesHere</prop>
<prop key="java.naming.factory.url.pkgs">yourPackagePrefixesGoHere</prop>
<!-- other key=values here -->
</props>
</property>
<!-- other properties here-->
</bean>
You can then specify other environment properties as needed and you can also simplify your configuration by using the Spring jee schema.
expanding on the above with an example for connecting to a remote activeMQ server in JBoss EAP7 using CAMEL Jms component.
You will need these 3 beans in your Spring XML application context:
<bean id="remoteQCF" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="${factoryJndiName}" />
<property name="jndiEnvironment">
<props>
<prop key="java.naming.provider.url">http-remoting://${remoteHost}:${remotePort}</prop>
<prop key="java.naming.factory.initial">org.jboss.naming.remote.client.InitialContextFactory</prop>
<!-- other key=values here <prop key="java.naming.factory.url.pkgs">yourPackagePrefixesGoHere</prop> -->
</props>
</property>
</bean>
<bean id="remoteQCFproxy"
class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
<property name="targetConnectionFactory" ref="remoteQCF" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</bean>
<bean id="jmsremote" class="org.apache.camel.component.jms.JmsComponent">
<property name="connectionFactory" ref="remoteQCFproxy" />
</bean>
where each ${xxx} denotes a value that you shall supply in place or with a property placeholder in your application context.
If you do not need a user and password to open a JMS queue connection, you may omit the second bean and reference directly the first bean as connectionFactory in the Camel JmsComponent bean.
The 'jmsremote' bean can then be used in CAML URI's like "jmsremote:queue:myQueue1"
Related
maybe I don't understand something correctly here. If one has configured the datasource like below
<bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSource" destroy-method="close" p:driverClassName="${jdbc.driverClassName}"
p:url="${db.url}" p:username="${db.username}" p:password="${db.password}"
p:initialSize="10"
p:minIdle="10"
p:maxIdle="20"
p:maxActive="50"
p:timeBetweenEvictionRunsMillis="30000"
p:minEvictableIdleTimeMillis="60000"
p:validationQuery="SELECT 1"
p:validationInterval="30000" />
Does it make sense to add the following properties to the
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaProperties">
<props>
<prop key="hibernate.default_schema">${jdbc.schema}</prop>
<prop key="hibernate.generate_statistics">${hibernate.generate_statistics}</prop>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.generate_statistics">true</prop>
<prop key="hibernate.cache.provider_configuration_file_resource_path">ehcache.xml</prop>
<prop key="hibernate.cache.region_prefix"></prop>
<prop key="hibernate.cache.use_structured_entries">true</prop>
<prop key="hibernate.c3p0.minPoolSize">5</prop>
<prop key="hibernate.c3p0.maxPoolSize">20</prop>
<prop key="hibernate.c3p0.timeout">600</prop>
<prop key="hibernate.c3p0.max_statement">50</prop>
<prop key="hibernate.c3p0.testConnectionOnCheckout">true</prop>
</props>
</property>
If no. Which one is better?
In my mind, what I have configured above is the pool twice. Once with Tomcat JDBC and another with c3p0.
The benefit that Spring gives you in this case is that you can provide your own DataSource and use the connection pool implementation you want/need regardless where the environment your app will be deployed and thus your application will be completely independent of the application server (in this case, Tomcat that works as servlet container).
From this point on, it depends on you to decide which connection pool implementation to use. IMO I would recommend using HikariCP rather than C3P0 or Tomcat. Disclaimer: I don't support HikariCP by any means, I'm just a happy user of the technology.
If you want spring to get datasource from c3p0 pool, just make the LocalContainerEntityManagerFactoryBean refer the c3p0 datasource bean.Here is an example.
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
...
</bean>
<bean id="dataSource" class = "com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<!-- these are C3P0 properties -->
<property name="acquireIncrement" value="${c3p0.acquireIncrement}" />
<property name="minPoolSize" value="${c3p0.minPoolSize}" />
<property name="maxPoolSize" value="${c3p0.maxPoolSize}" />
<property name="maxIdleTime" value="${c3p0.maxIdleTime}" />
</bean>
You can config the properties as you wish.
You need to add c3p0 dependency into your project:
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version><!--Maybe this is not the newest version-->
<type>jar</type>
<scope>compile</scope>
</dependency>
I am wondering why don't you use JNDI to provide the data source?Tomcat as an example,in the $TOMCAT_HOME/Context.xml、Server.xml:
<Resource name="jdbc/sample" auth="Container"
type="com.mchange.v2.c3p0.ComboPooledDataSource"
username=...
password=...
url=...
driverClassName=...
otherAttributes...
/>
To reference the JNDI datasource please see here.
About the C3P0 pooling and spring see here and here.
I am using an Oracle connection pool by using the following Spring configuration for my datasource:
<bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource">
<property name="connectionCachingEnabled" value="true" />
<property name="URL" value="myUrl" />
<property name="user" value="myUserName" />
<property name="password" value="myPassword" />
<property name="connectionCacheProperties">
<util:properties>
<prop key="InitialLimit">5</prop>
<prop key="MinLimit">5</prop>
<prop key="MaxLimit">30</prop>
<prop key="MaxStatementsLimit">20</prop>
</util:properties>
</property>
</bean>
I would like to expose the statistics of this pool via JMX so that I can monitor the pool to see how many connections are in the pool, how many are busy, etc.
I am connecting to an Oracle 10g server with the oracle 11.2.0.3.0 jdbc driver.
How do I do this?
Try this -
MethodNameBasedMBeanInfoAssembler
public class MethodNameBasedMBeanInfoAssembler
Subclass of AbstractReflectiveMBeanInfoAssembler that allows to
specify method names to be exposed as MBean operations and attributes.
JavaBean getters and setters will automatically be exposed as JMX
attributes.
You can supply an array of method names via the managedMethods
property. If you have multiple beans and you wish each bean to use a
different set of method names, then you can map bean keys (that is the
name used to pass the bean to the MBeanExporter) to a list of method
names using the methodMappings property.
If you specify values for both methodMappings and managedMethods,
Spring will attempt to find method names in the mappings first. If no
method names for the bean are found, it will use the method names
defined by managedMethods.
For example -
...
<bean id="mbeanServer" class="org.springframework.jmx.support.MBeanServerFactoryBean">
<property name="locateExistingServerIfPossible" value="true" />
</bean>
<bean id="mbeanExporter" class="org.springframework.jmx.export.MBeanExporter">
<property name="assembler">
<bean class="org.springframework.jmx.export.assembler.MethodNameBasedMBeanInfoAssembler">
<property name="managedMethods">
<list>
<value>getNumActive</value>
<value>getMaxActive</value>
<value>getNumIdle</value>
<value>getMaxIdle</value>
<value>getMaxWait</value>
<value>getInitialSize</value>
</list>
</property>
</bean>
</property>
<property name="beans">
<map>
<entry key="dataSource:name=DataSource" value-ref="dataSource"/>
</map>
</property>
<property name="server" ref="mbeanServer" />
</bean>
For Enabling JMX in Hibernate, EhCache, Quartz, DBCP and Spring
Kindly refer the http://nurkiewicz.blogspot.com/2011/12/enabling-jmx-in-hibernate-ehcache-qurtz.html
I want to make DataSource in Spring through JNDI. All the configuration are given.
Can someone tell me what is wrong with the configuration.
One thing I would like to mention here is that JNDI DS is hosted on JBoss server which does not host the Spring application.
Configuration
datasource-ds.xml
<?xml version="1.0" encoding="UTF-8"?>
<datasources>
<local-tx-datasource>
<jndi-name>jdbc/wc-mysql</jndi-name>
<connection-url>jdbc:mysql://xx.xx.xx.xx:3306/club</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<user-name>club</user-name>
<password>club</password>
<exception-sorter-class-name>
org.jboss.resource.adapter.jdbc.vendor.MySQLExceptionSorter
</exception-sorter-class-name>
<min-pool-size>5</min-pool-size>
<max-pool-size>20</max-pool-size>
<use-java-context>false</use-java-context>
<metadata><type-mapping>mySQL</type-mapping></metadata>
</local-tx-datasource>
</datasources>
configContext.xml
<bean id="wcDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/wc-mysql" />
<property name="jndiEnvironment">
<props>
<prop key="java.naming.provider.url">jnp://yy.yy.yy.yy:1099</prop>
<!--
<prop key="java.naming.factory.initial">
org.springframework.mock.jndi.SimpleNamingContextBuilder
</prop>
<prop key="java.naming.factory.url.pkgs">yourPackagePrefixesGoHere</prop> -->
<!-- other key=values here -->
</props>
</property>
<!-- other properties here-->
</bean>
Exception
Caused by: javax.naming.NameNotFoundException: Name jdbc is 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)
I have made few changes and Its now working fine.
A JNDI Template must be initialized with the JNP properties. And URL to JBoss server has to be in that properties.
configContext.xml
<bean id="wcJndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.factory.initial">org.jnp.interfaces.NamingContextFactory</prop>
<prop key="java.naming.provider.url">jnp://jndi.myURL.me:1099</prop>
<prop key="java.naming.factory.url.pkgs">org.jboss.naming:org.jnp.interfaces</prop>
<prop key="jnp.disableDiscovery">true</prop>
</props>
</property>
</bean>
<bean id="wcDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/wc-mysql"/>
<property name="resourceRef" value="false"/>
<property name="jndiTemplate" ref="wcJndiTemplate" />
</bean>
But after doing that changes I was facing an exception
java.lang.ClassNotFoundException: org.jnp.interfaces.NamingContextFactory
So I found a link mentioning to include a dependency of jbossall-client.jar in the POM to resolve the issue. So the pom changes are
<dependency>
<groupId>jboss</groupId>
<artifactId>jbossall-client</artifactId>
<version>4.2.2.GA</version>
</dependency>
Every thing seems to be working fine.
Thanks.
There is no problem with your remote JNDI as this line
<use-java-context>false</use-java-context>
will take care of it.
You have problem with your JNDI name value:
javax.naming.NameNotFoundException: Name jdbc is not bound in this Context
Change this in your applicationConfig.xml
<property name="jndiName" value="jdbc/wc-mysql" />
to
<property name="jndiName" value="java:/jdbc/wc-mysql"></property>
It should work
We are trying to upgrade from Spring 1.2.8 to Spring 3.0
However when we are trying to configure txManager for Websphere I always get a class cast exception.
We tried based on the example provided by IBM which doesn't work.
I am using WAS 7.0 and Spring.3.0.5 and hibernate.3.6.jars...
Here is the Spring config:
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="ewpDataSource" />
<property name="mappingResources">
<list>
<value>com/fme/example/model/Person.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.default_schema">ORIG</prop>
<prop key="hibernate.cglib.use_reflection_optimizer">false</prop>
<prop key="hibernate.use_sql_comments">true</prop>
<prop key="hibernate.transaction.factory_class">
org.hibernate.transaction.JTATransactionFactory
</prop>
<prop key="hibernate.transaction.manager_lookup_class">
org.hibernate.transaction.WebSphereExtendedJTATransactionLookup
</prop>
</props>
</property>
</bean>
<!-- Our Data source --->
<bean id="ewpDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/TOI_ORIG" />
</bean>
<!--- Get the Web sphere Specific TX manager -->
<bean id="transactionManager"
class="org.springframework.transaction.jta.WebSphereUowTransactionManager"/>
</beans>
I read this article and tried exactly as specified.
http://www.ibm.com/developerworks/websphere/techjournal/0609_alcott/0609_alcott.html
And also tried
http://robertmaldon.blogspot.com/2006/09/using-websphere-transaction-manager.html
But we are getting this Exception.
Caused by: java.lang.IllegalStateException: Cannot convert value of type [org.springframework.transaction.jta.WebSphereUowTransactionManager] to required type [javax.transaction.TransactionManager] for property 'transactionManager': no matching editors or conversion strategy found
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:231)
at org.springframework.beans.BeanWrapperImpl.convertIfNecessary(BeanWrapperImpl.java:447)
I see that the class
org.springframework.transaction.jta.WebSphereUowTransactionManager
provided for Websphere doesn't implement javax.transaction.TransactionManager any where in the hierarchy.
Any idea?
I got it working. In addition to the above hibernate settings here is what I did.
The object of type WebSphereUowTransactionManager is not an instance of
javax.transaction.TransactionManager
but there is superclass method inside WebSphereUowTransactionManager
called getTransactionManager()
this returns object of type javax.transaction.TransactionManager
<bean id="wasUOWTxnManagerObj"
class="org.springframework.transaction.jta.WebSphereUowTransactionManager"/>
<!--
Now call get getTransactionManager on WebSphereUowTransactionManager
object.
-->
<bean id="tranSactionManager"
class="javax.transaction.TransactionManager"
factory-bean="wasUOWTxnManagerObj"
factory-method="getTransactionManager">
</bean>
With this change now you can use WebSphereUowTransactionManager. Hope this helps.
When using Spring you usually don't need to use javax.transaction.TransactionManager directly.
Use transaction management approaches provided by Spring instead, see 10. Transaction Management.
What is this error about? "No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here".
My spring config file looks something like this.
<bean id="jndiDataSource"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:/devDS</value>
</property>
</bean>
<bean id="stsaDBFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="jndiDataSource" />
<property name="annotatedClasses">
<list>
<value>xx.yy.zz.User</value>
<value>xx.yy.UserResponse</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbmddl.auto">create</prop>
</props>
</property>
</bean>
<!-- ################################### Aspects ################################################## -->
<bean id="txManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref local="stsaDBFactory" />
</property>
</bean>
All the DAO test passes when i test them outside of the container using junit. When I deploy it in jBoss as a portal app,I get this exception. Also it works fine if i remove the portal specific configuration and make it a simple web app and deploy it on jboss.Any idea?
You have defined a TransactionManager in your spring config but you are trying to execute a hibernate query in a method that is not transactional. Try adding #Transactional to your method or class.
I got around this problem by specifying the current_session_context_class in hibernate config to be "thread", as per the simple configuration shown in the hibernate configuration documentation.
But it recommends that its not safe for production usage.
Trying to add the following in your hibernate config should also help:
<property name="current_session_context_class">org.hibernate.context.ThreadLocalSessionContext</property>
Check out http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/architecture.html#architecture-current-session for more details.