I wonder how object (if it matter I need EJB) can be plugged to JBoss (5.0) with JNDI?
I have following bean definition in my Spring applicationContext.xml:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<context:annotation-config/>
<bean id="myServiceFacade" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="MyServiceFacadeBean/remote"/>
<property name="cache" value="true"/>
<property name="lookupOnStartup" value="true"/>
<property name="jndiEnvironment">
<props>
<prop key="java.naming.factory.initial">org.jnp.interfaces.NamingContextFactory
</prop>
<prop key="java.naming.provider.url">localhost:1099</prop>
<prop key="java.naming.factory.url.pkgs">org.jboss.naming:org.jnp.interfaces
</prop>
</props>
</property>
<property name="proxyInterface" value="my.company.service.facade.MyServiceFacade"/>
</bean>
when I try to run JBoss I get:
Caused by: javax.naming.NameNotFoundException: MyServiceFacadeBean/remote
at org.jboss.ha.jndi.HAJNDI.lookupRemotely(HAJNDI.java:264)
at org.jboss.ha.jndi.HAJNDI.lookup(HAJNDI.java:205)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.jboss.ha.framework.interfaces.HARMIClient.invoke(HARMIClient.java:318)
at $Proxy165.lookup(Unknown Source)
Maybe some additional steps should be made for registering objects with JBoss/JNDI?
Note, I've tried already to put ejb specific files to JBoss (jboss.xml, ejb-jar.xml) but that doesn't help.
How do you loop-up remote in your DataSource? But I am sure you can't get it from your MyServiceFacadeBean.
in applicationContext.xml:
<property name="jndiName" value="remote"/>
While loooping up,
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("java:comp/env/remote");
DataSource ds = (DataSource)envCtx.lookup("remote");
or you could make an intermediate step so you don't have to specify "java:comp/env" for every resource you retrieve:
Context ctx = new InitialContext();
Context envCtx = (Context)ctx.lookup("java:comp/remote");
DataSource ds = (DataSource)envCtx.lookup("remote");
Hope it helps.
Related
I'm migrating an application from OC4J to WebLogic 12c and the Spring beans are giving an error I can't figure out how to solve. My question is what can be the cause of this error.
I have the following bean for the JNDI lookup:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="${datasource.jndiname}" />
<property name="lookupOnStartup">
<value>false</value>
</property>
<property name="proxyInterface">
<value>javax.sql.DataSource</value>
</property>
</bean>
The value ${datasource.jndiname} is expected to come from a config.properties file with the following line:
server.database.datasource=${datasource.jndiname}
And the value of server.database.datasource comes from a config.filter file with the line:
server.database.datasource=jdbc/DATASOURCE
This works fine with OC4J and it also works when I replace the ${datasource.jndiname} to its value jdbc/DATASOURCE in WebLogic, but it gives me the following error if I keep the reference (and I need to keep it):
JndiObjectTargetSource failed to obtain new target object; nested exception is javax.naming.NameNotFoundException: While trying to lookup '${datasource.jndiname}' didn't find subcontext '${datasource'. Resolved ''; remaining name '${datasource/jndiname}'
After some research, I found a property for the bean that fixed the error. Setting the property resourceRef to false makes the reference ${datasource.jndiname} work as expected.
In the final code shown below I also added a JndiTemplate.
<bean id="dsJndiTemplate" class="org.springframework.jndi.JndiTemplate">
<property name="environment">
<props>
<prop key="java.naming.provider.url">t3://localhost:7001</prop>
<prop key="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory</prop>
</props>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="${datasource.jndiname}" />
<property name="resourceRef" value="false"/>
<property name="lookupOnStartup" value="false"/>
<property name="proxyInterface" value="javax.sql.DataSource"/>
<property name="jndiTemplate">
<ref local="dsJndiTemplate" />
</property>
</bean>
First of all, I can't use Spring's #Transactional annotation. I have to use exactly JTA which in out EJB-container. Currecntly I'm using JBoss AS 7.0 Web-Profile. So what I need to do is configure Hibernate's session factory to correctly work with JTA-transaction inside the Spring's Envirnoment. My current configuration:
piece of the context.xml configuration:
<tx:annotation-driven/>
<tx:jta-transaction-manager />
<!-- Some other beans -->
<bean id="userTransaction" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/UserTransaction"></property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.badmitrii.db.entity.Employee</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">false</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="userTransaction" ref="userTransaction"></property>
</bean>
DAO-method:
public Player getPlayerById(Integer id){
try {
userTransaction.begin();
} catch (Exception e) { }
//Here is obtaining a Criteria object and setting Restrictions
try {
userTransaction.commit();
} catch (Exception e) { }
return (Player) criteria.uniqueResult();
}
But, I got the following excpetion when I was trying to get Session in the DAO method:
org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:134)
org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1024)
com.badmitrii.db.dao.EmployeeDAOImpl.getEmployeeById(EmployeeDAOImpl.java:34)
com.badmitrii.EmployeeListController.getEmployeeById(EmployeeListController.java:42)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:483)
org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:777)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:706)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857)
javax.servlet.http.HttpServlet.service(HttpServlet.java:734)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
How to configure it correctly?
First of all remove the declaration for JtaTransactionManager as that is already provided by <tx:jta-transaction-manager />.
Next there is no reason why you wouldn't be able to use #Transactional in a JTA environment that is the whole point of declarative tx management.
You should wire the configured jta transactionmanager to the LocalSessionFactoryBean to switch out the used CurrentSessionContext.
<tx:annotation-driven/>
<tx:jta-transaction-manager />
<!-- Some other beans -->
<bean id="userTransaction" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/UserTransaction"></property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jtaTransactionManager" ref="transactionManager" />
<property name="annotatedClasses">
<list>
<value>com.badmitrii.db.entity.Employee</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">false</prop>
</props>
</property>
</bean>
Then in your cod eyou can simply do something like this
#Transactional
public Player getPlayerById(Integer id){
//Here is obtaining a Criteria object and setting Restrictions
return (Player) criteria.uniqueResult();
}
Update:
For JBoss the <tx:jta-transaction-manager /> doesn't work due to fact that the TransactionManager for JTA is registered in JNDI under the name java:jboss/TransactionManager instead of one of the well-known names. You will need to declare the JtaTransactionManager bean yourself and remove the <tx:jta-transaction-manager /> element. For the lookup you need to specify the transactionManagerName or do a JNDI lookup yourself.
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManagerName" value="java:jboss/TransactionManager" />
</bean>
The UserTransaction is registered under the default name so you can omit the injection of it in the JtaTransactionManager as it will do the lookup itself.
i want to use Hikari CP in my Spring 4.0.3 context but seems i am missing something.
My bean configuration looks like:
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<constructor-arg>
<bean class="com.zaxxer.hikari.HikariConfig">
<constructor-arg>
<props>
<prop key="dataSource.driverClassName">${database.driver}</prop>
<prop key="dataSource.jdbcUrl">${database.database.jdbc.url}</prop>
<prop key="dataSource.port">${database.port}</prop>
<prop key="dataSource.databaseName">${database.name}</prop>
<prop key="dataSource.user">${database.user}</prop>
<prop key="dataSource.password">${database.password}</prop>
</props>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
but i get an exception:
Caused by: java.lang.IllegalArgumentException: one of either dataSource or dataSourceClassName must be specified
at com.zaxxer.hikari.HikariConfig.validate(HikariConfig.java:655)
at com.zaxxer.hikari.HikariDataSource.<init>(HikariDataSource.java:66)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:148)
... 15 more
i have tried to configure dataSourceClassName using the HSQL org.hsqldb.jdbc.JDBCDataSource
that way:
<prop key="dataSourceClassName">org.hsqldb.jdbc.JDBCDataSource</prop>
also that way:
<prop key="dataSource.ClassName">org.hsqldb.jdbc.JDBCDataSource</prop>
both times i got the following exception:
Caused by: java.lang.RuntimeException: java.beans.IntrospectionException: Method not found: setPort
at com.zaxxer.hikari.util.PropertyBeanSetter.setProperty(PropertyBeanSetter.java:109)
at com.zaxxer.hikari.util.PropertyBeanSetter.setTargetFromProperties(PropertyBeanSetter.java:61)
at com.zaxxer.hikari.pool.HikariPool.initializeDataSource(HikariPool.java:497)
... 23 more
Caused by: java.beans.IntrospectionException: Method not found: setPort
at java.beans.PropertyDescriptor.<init>(PropertyDescriptor.java:110)
at com.zaxxer.hikari.util.PropertyBeanSetter.setProperty(PropertyBeanSetter.java:97)
... 25 more
Can someone show me a working Hikari CP Spring 4 bean configuration that works with a HSQL DB?
I am not interested in MySql, PG etc. because i know how to get them working. But i can't manage to get it done with HSQL.
Thanks,
Tech used: Java8, Spring 4.0.3, HSQL 2.3.2
one way to get the job done is to provide an instance of a DataSource object:
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<constructor-arg>
<bean class="com.zaxxer.hikari.HikariConfig">
<property name="dataSource">
<bean class="org.hsqldb.jdbc.JDBCDataSource">
<property name="url" value="${database.database.jdbc.url}"/>
<property name="databaseName" value="${database.name}"/>
<property name="user" value="${database.user}"/>
<property name="password" value="${database.password}"/>
</bean>
</property>
</bean>
</constructor-arg>
</bean>
for sure there are other solutions.
HTH,
Some of your properties in your example do not need the prefix 'dataSource' if you are using a driver-class.
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<constructor-arg>
<bean class="com.zaxxer.hikari.HikariConfig">
<constructor-arg>
<props>
<prop key="driverClassName">${database.driver}</prop>
<prop key="jdbcUrl">${database.database.jdbc.url}</prop>
<prop key="username">${database.user}</prop>
<prop key="password">${database.password}</prop>
</props>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
And port and databaseName can be included in the jdbcUrl.
For a pure Java-config solution, I've used the following (in a class with a #Configuration annotation and included in the component-scan-path):
...
#Bean
public DataSource dataSource() {
return new HikariDataSource(hikariConfig());
}
private HikariConfig hikariConfig() {
HikariConfig config = new HikariConfig();
config.setDriverClassName(driverClassName);
config.setJdbcUrl(jdbcUrl);
config.setUsername(username);
config.setPassword(password);
return config;
}
...
HTH
Tested under HikariCP 2.3.8 and Hibernate 4.3.8.Final:
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
<constructor-arg>
<props>
<prop key="dataSourceClassName">org.postgresql.ds.PGSimpleDataSource</prop>
<prop key="dataSource.user">${database.username}</prop>
<prop key="dataSource.password">${database.password}</prop>
<prop key="dataSource.databaseName">${database.databaseName}</prop>
<prop key="dataSource.serverName">${database.serverName}</prop>
<prop key="connectionTestQuery">SELECT 1</prop>
</props>
</constructor-arg>
</bean>
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<constructor-arg ref="hikariConfig" />
</bean>
For the dataSourceClassName, looks at the popular datasource class names table.
ConnectionTestQuery is required for postgresql as per https://github.com/brettwooldridge/HikariCP/issues/225, shouldn't be needed when using a latest jdbc driver version.
I am using Spring 3.0 and Hibernate 3.6 DataSource is defined as
<bean id="test-pool"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
<property name="url"
value="jdbc:sqlserver://Machine:1433;databaseName=TEST;maxPoolSize=100;
minPoolSize=5;acquireIncrement=5;checkoutTimeout=5000;maxStatements=100;idleConnectionTestPeriod=3000" />
<property name="username" value="${user}" />
<property name="password" value="${database.password}"/>
</bean>
Session Factory with data source is
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="test-pool"/>
<property name="configLocation" value="WEB-INF/classes/test.hibernate.cfg.xml"></property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
</props>
</property>
</bean>
In Factory class:
LocalSessionFactoryBean localfactorybean = (LocalSessionFactoryBean)AppContext.getBean("&sessionFactory");
Configuration configuration = localfactorybean.getConfiguration();
SessionFactory sessionFactory = configuration.buildSessionFactory();
But I am getting following exception
org.hibernate.HibernateException: No local DataSource found for configuration - 'dataSource' property must be set on LocalSessionFactoryBean
at org.springframework.orm.hibernate3.LocalDataSourceConnectionProvider.configure(LocalDataSourceConnectionProvider.java:49)
at org.hibernate.connection.ConnectionProviderFactory.newConnectionProvider(ConnectionProviderFactory.java:143)
at org.hibernate.connection.ConnectionProviderFactory.newConnectionProvider(ConnectionProviderFactory.java:84)
at org.hibernate.cfg.SettingsFactory.createConnectionProvider(SettingsFactory.java:459)
at org.hibernate.cfg.SettingsFactory.buildSettings(SettingsFactory.java:91)
What is wrong with my current code?
I get rid of this exception if I explicitly get SessionFactory again like this:
SessionFactory sessionFactory = (SessionFactory) AppContext.getBean("sessionFactory");
As you can see its not neat and I want to get rid of it.
What exact version of Hibernate are you using? This article suggests that there is a problem with 3.2.1 which has the same symptoms as you have. Maybe time to update your version - hibernate is now at 4.1.4
I use Spring-configured jms template with tibco jms library.
I get jms connection factory and topic with JNDI and these objects are not null. But when I try to send message or add listener I get this exception:
For listener:
Exception in thread "main" org.springframework.jms.InvalidDestinationException: Can not send into foreign destinations; nested exception is javax.jms.InvalidDestinationException: Can not send into foreign destinations
at org.springframework.jms.support.JmsUtils.convertJmsAccessException(JmsUtils.java:277)
at org.springframework.jms.support.JmsAccessor.convertJmsAccessException(JmsAccessor.java:168)
at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:474)
at org.springframework.jms.core.JmsTemplate.receiveSelected(JmsTemplate.java:700)
at org.springframework.jms.core.JmsTemplate.receive(JmsTemplate.java:682)
at org.springframework.jms.core.JmsTemplate.receive(JmsTemplate.java:674)
For sender:
Exception in thread "main" org.springframework.jms.InvalidDestinationException: Invalid or foreigndestination; nested exception is javax.jms.InvalidDestinationException: Invalid or foreigndestination
at org.springframework.jms.support.JmsUtils.convertJmsAccessException(JmsUtils.java:277)
at org.springframework.jms.support.JmsAccessor.convertJmsAccessException(JmsAccessor.java:168)
at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:474)
at org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:539)
at org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:531)
Client app is working with the same topic without problems (so jms server is running). Do you have any ideas? I read about this exception in javadoc, but can't find how to understand the root issue and fix it.
Thanks
UPD:
JMS-related part of config:
<bean id="JmsFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="${jms.factory}"/>
<property name="proxyInterface" value="javax.jms.TopicConnectionFactory" />
<property name="lookupOnStartup" value="false" />
<property name="jndiEnvironment">
<props>
<prop key="java.naming.provider.url">${jms.namingProvider}</prop>
<prop key="java.naming.factory.initial">${jms.namingFactory}</prop>
<prop key="java.naming.referral">${jms.namingReferral}</prop>
<prop key="java.naming.security.credentials">${jms.securityCredentials}</prop>
<prop key="java.naming.security.principal">${jms.securityPrincipal}</prop>
</props>
</property>
</bean>
<bean id="JmsTopic" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="${jms.topic}"/>
<property name="proxyInterface" value="javax.jms.Topic" />
<property name="lookupOnStartup" value="false" />
<property name="jndiEnvironment">
<props>
<prop key="java.naming.provider.url">${jms.namingProvider}</prop>
<prop key="java.naming.factory.initial">${jms.namingFactory}</prop>
<prop key="java.naming.referral">${jms.namingReferral}</prop>
<prop key="java.naming.security.credentials">${jms.securityCredentials}</prop>
<prop key="java.naming.security.principal">${jms.securityPrincipal}</prop>
</props>
</property>
</bean>
<bean id="UserCredentialsConnectionFactory"
class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
<property name="targetConnectionFactory">
<ref bean="JmsFactory" />
</property>
<property name="username" value="${jms.user}" />
<property name="password" value="${jms.password}" />
</bean>
<bean id="JmsTemplate"
class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory"
ref="UserCredentialsConnectionFactory" />
<property name="defaultDestination">
<ref bean="JmsTopic"/>
</property>
<property name="pubSubDomain" value="true" />
</bean>
It sounds like you have it configured so that it is attempting to create a destination rather than do a jndi lookup to get the destination that has been defined on the EMS instance.
You need to post your spring config to be sure though.
edit: if you set a destinationname on the JmsTemplate and provide it with a JndiDestinationResolver then it should work