Tomcat context.xml Parameter declaration accessed in Spring's application context - java

One of our apps declare some parameters in Tomcat's context.xml as such:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<Parameter name="defaultSchema" override="true" value="demo"/>
<Resource
auth="Container"
description="DB Connection for Local Jazzee"
driverClassName="oracle.jdbc.OracleDriver"
. . .
/>
</Context>
And then in Spring's applicationContext.xml we are able to use that parameter when we instantiate some beans:
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.default_schema">${defaultSchema}</prop>
. . .
</bean>
And that works fine.
Problem I'm having is that I'm trying to duplicate this in another application, and it's not working. When I try to start the app, I get the error:
Invalid bean definition with name 'sessionFactory' defined in class path resource [db/applicationContext.xml]: Could not resolve placeholder 'defaultSchema'
It's the same developer Tomcat instance in both cases, so the Tomcat version is the same. The Spring library versions appear to be the same as well. Also, if I hardcode the schema name in the application context, it works fine. So the dataSource is fine.
Any thoughts on what might be breaking this functionality?

Related

Hibernate LocalSessionFactoryBean, setMappingDirectoryLocations doesn't seem to be working

I'm using Spring 5 and Hibernate 5 together, and I'm configuring Hibernate mapping files in:
org.springframework.orm.hibernate5.LocalSessionFactoryBean like this in my applicationContext.xml file:
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="mappingDirectoryLocations" value="com/myorg/division/myapp/model" />
But I'm getting this error run-time error when I deploy the WAR file to my local Weblogic server:
Deployment Message : weblogic.application.ModuleException: java.io.FileNotFoundException: ServletContext resource [/com/
myorg/division/myapp/model] cannot be resolved to absolute file path - web application archive not expanded?
This should do the work
<property name="packagesToScan" value="com.myorg.division.myapp.model" />

Tomcat connection pool with MyBatis

I was wondering if anyone has any code examples for setting up a connection pool in Tomcat (7 or later) using MyBatis as the ORM.
I presume I need to add a resource to my context.xml file in my Tomcat conf folder and then link that to MyBatis. I've had a look and any tutorials I have found seem to be Spring specific. Does anyone have a simple tutorial or can they outline the steps required to get this up and running?
There is this old entry in the iBatis FAQ that should still be applicable to myBatis: How do I use a JNDI DataSource with iBATIS in Tomcat?.
You can google for the details to configure a datasource in your Tomcat version, then configure MyBatis as well (it's different than the iBatis configuration):
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="JNDI">
<property name="data_source" value="java:comp/env/jdbc/yourDatasourceName"/>
</dataSource>
</environment>
There are a number of ways you can do this. I am assuming that you mean to implement Tomcat (as opposed to Spring) managed connection pooling. I have tested on MySQl/Spring 4/Mybatis-spring 1.1 stack.
Figure out the connection pooling mechanism you want to implement (C3P0/DBCP etc).
If you want to use your database as a JNDI data source, then you have to declare it as a resource in Tomcat settings. There are a number of ways to do this. You can follow this well written guide Tomcat JNDI connection pooling. I generally add the following entry in context.xml located in the META-INF directory of my app:
<Context>
<Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource" maxTotal="100" maxIdle="30" maxWaitMillis="10000" username="javauser" password="javadude" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/javatest"/>
</Context>
This file is used by Tomcat to invoke its own default connection pool, which in this case would be DBCP 2. You can tweak its settings by adding more parameters (like removeAbandonedOnBorrow=true) in the Resource element above. You should put the driver jar (eg MySQL Connector Jar) of your database in Tomcat's lib folder.
After this, depending on your Mybatis implementation (XML or bean based), you can inject this data source into Mybatis. If you are doing it the bean way, you can do it like this:
<bean id="dbDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/TestDB"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dbDataSource" />
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dbDataSource" />
<property name="typeAliasesPackage" value="com.example.model"/>
<property name="mapperLocations" value="classpath*:*.xml" />
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.example.dao" />
</bean>
MapperScannerConfigurer is necessary because it searches the directories given to it to find mapper xml files. You can also use the old way of defining a mybatis-config.xml file by injecting the file's location in the sqlSessionFactory bean in its configLocation property.

Unable to load beans from Application Context in junit test

I'm trying to implement a group of tests for my app. In this case, I have some mybatis mappers whose beans are defined in my applicationContext.xml. For example:
<bean id="usersMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="com.myapp.dao.UserMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
I've been looking for hours how to implement junit tests properly because some internet posts are deprecated or not up to date. This is my junit class actually:
#ContextConfiguration(locations = {"classpath:*applicationContext.xml"})
#RunWith(SpringJUnit4ClassRunner.class)
public class GroupTest {
#Autowired
ApplicationContext context;
#Test
public void testCreateGroup() throws SQLException {
UserMapper um = (UserMapper)context.getBean("usersMapper");
}
}
There are no errors during the startup. When I try to get the bean usersMapper returns an exception (There is no bean definition..) Maybe, is not loading the properly applicationContext?
I also tried Mockito with no success. I've read it does cool things, but is it capable of loading the context as well as Spring? When I call the getUsers method from UserMapper, it returns null. This is my implementation:
#ContextConfiguration(locations = {"classpath:*applicationContext.xml"})
#RunWith(SpringJUnit4ClassRunner.class)
public class GroupTest {
#Mock
private UserMapper userMapper;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testCreateGroup() throws SQLException {
userMapper.getUsers();
}
}
For the record... my applicationContext.xml is placed in /src/main/webapp/WEB-INF/applicationContext.xml
Hope you can guide me the right way. Thank you
Edit1: applicationContext.xml and context.xml added:
<?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: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.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/adminDB"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="/WEB-INF/mybatis-config.xml" />
</bean>
<bean id="usersMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="mapperInterface" value="es.unican.meteo.dao.UserMapper" />
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
</beans>
It seems that Peter Hart solution loads the applicationContext.xml but a new problem appears. I need to use a jndi Resource in my app (reference included in applicationContext.xml). Is this no possible in test environment?
The exception shows the following:
Caused by: javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
This is my context.xml
<Context>
<Resource name="jdbc/adminDB" auth="Container" type="javax.sql.DataSource"
maxActive="20" maxIdle="10" username="***" password="***"
driverClassName="org.apache.derby.jdbc.ClientDriver"
url="jdbc:***"/>
</Context>
The problem is that you've requested a classpath resource, and WEB-INF/applicationContext.xml is probably not on the classpath (it usually wouldn't be).
You could try moving the applicationContext.xml to somewhere on the classpath. I'm guessing that you are using maven, in which case, this would usually either be src/main/resources, or src/test/resources (if this is specific to a particular test, rather than a 'real' application context file). I would also fix your #ContextConfiguration as #ohiocowboy suggests (assuming you put it directly in that directory, as things will generally work better if you're explicit about the location).
If your application context absolutely needs to be in WEB-INF/applicationContext.xml, you might try using file:src/main/webapp/WEB-INF/applicationContext.xml. If you run from the base directory of the project with mvn test, it should work, and it would probably work from the eclipse test runner also (no idea about Idea or NetBeans, but my guess is that it might work).
Your application context is not being loaded properly. The locations attribute of the #ContextConfiguration annotation should be "classpath:main/webapp/WEB-INF/applicationContext.xml", "classpath:**/applicationContext.xml" or "classpath*:applicationContext.xml". When you run the test, the application is not deployed, hence WEB-INF will not be in the classpath(unless you have added it to the test classpath yourself).
When using a mock object, you need to provide mock implementations for the methods that are going to be called. The getUsers() method is returning null because you have not set the desired result. You can check the mockito website for examples at http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html.
try
#ContextConfiguration(locations = {"classpath:/applicationContext.xml"})
UPDATE
Actually that doesn't work either because. The applicationContext.xml isn't on the classpath. It needs to be moved into the WEB-INF/classes directory.

externalizing terracottaconfig property in ehcache.xml file inside Spring framework

There is this tag <terracottaConfig url="host1:9510,host2:9510,host3:9510"/> in ehcache.xml file inside spring web application. I want to externalize url attribute of this tag. Value of URL should be replaced by a property from external file. It will be very helpful if you suggest any solution to this problem.
You can put something like this -
<terracottaConfig url="${terracotta.config.location}" /> , however the big catch is that this will be loaded only from the system properties. It is not resolved from PropertyPlaceHolder as it is not a Spring configuration file.
So if you want to use an external config file, you will basically have to programatically set this system property before the Spring Application starts loading up the ehcache.xml file - one way to do that will be write your custom ServletContextListener to load up your properties file and set the system property based on that, this way when the ehcache.xml is loaded up it would be able to resolve the place holder properly.
Your answer helped me to solve my problem. I just want to add that instead of setting system property through program, I am using util:properties as follows
<bean id="sysProperties" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" value="#{#systemProperties}"/>
<property name="targetMethod" value="putAll"/>
<property name="arguments">
<util:properties>
<prop key="propertyname_used_in_ecache_xml">#{proerties_defined_using_property_factory['propertyname_defined_in_external_properties_file']}</prop>
</util:properties>
</property>
</bean>
<bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" depends-on="sysProperties">
<property name="configLocation">
<value>classpath:ehcache.xml</value>
</property>
</bean>

instantiating spring bean outside the container (for testing)

I have following in my applicaionContext.xml
<bean id="IbatisDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#123.210.85.56:1522:ORCL"/>
<property name="username" value="mydb"/>
<property name="password" value="mydbpwd"/>
</bean>
<bean id="myMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<property name="configLocation" value="classpath:sql-map-config-oracle.xml"/>
<property name="dataSource" ref="IbatisDataSource"/>
</bean>
then in my code I have:
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
SqlMapClient sqlclient = (SqlMapClient) ctx.getBean("myMapClient");
doing this gives me the following error:
Error creating bean with name
'myMapClient' defined in class
path resource
[applicationContext.xml]: Invocation
of init method failed; nested
exception is
java.lang.NoClassDefFoundError:
com/iplanet/ias/admin/common/ASException
I don't understand why is it looking for that class? I am trying to do everything outside the container. So it should not even be looking for that class...but nonetheless just to make it work I tried looking for class called ASException so I could put it on the classpath but no where can I find ASException class.
Any pointers?
Images of stack trace and my compile test / run test libs
Edit
Solution:
Even though I thought everything was outside the container...there was ONE thing that was not outside the container.
Notice the property configLocation:
<property name="configLocation" value="classpath:sql-map-config-oracle.xml"/>
actual content of sql-map-config-oracle.xml is
<sqlMapConfig>
<settings enhancementEnabled="true" useStatementNamespaces="true" />
<transactionManager type="JDBC">
<dataSource type="JNDI">
<property name="DataSource" value="my/jndi/mydb" />
</dataSource>
</transactionManager>
<sqlMap resource="somemapping.xml"/>
</sqlMapConfig>
JNDI stuff does not need to be there!
sql-map-config-oracle.xml should simply be:
<sqlMapConfig>
<settings enhancementEnabled="true" useStatementNamespaces="true" />
<sqlMap resource="somemapping.xml"/>
</sqlMapConfig>
You definitely have a runtime dependency issue as #Cletus said org.springframework.orm.ibatis.SqlMapClientFactoryBean was compiled with com.iplanet.ias.admin.common.ASException but now you don't have it in your classpath -- Spring can't find it. You should Look at the source for SqlMapClientFactoryBean to see where ASException is called -- Spring should have a dist with all it's dependencies in it, you can also look in there when doing your investigation.
This class was found during compilation but not during running:
com/iplanet/ias/admin/common/ASException
So when you're running the program, it can't seem to find this class, which belongs to the Sun app or portal server that you're using. In short: it's a classpath error.

Categories

Resources