I need to configure hibernate to load the hibernate.cfg.xml from a custom location on an OSGI bundle on karaf. I need to be able to edit the configuration without editing the JAR file which seems to be the only option available. I am using the following class to load the Hibernate SessionFactory as described on the hibernate documentation, but it seems there are no way to configure this on the SessionFactory returned by the Hibernate OSGI module exposing this service. I have been researching this problem several days but I can not find a solution. I am using Hibernate 4.3.11.Final. Any help is very much appreciated, Thanks
public class HibernateUtil {
private static SessionFactory sf;
public static Session getSession() {
return getSessionFactory().openSession();
}
private static SessionFactory getSessionFactory() {
if ( sf == null ) {
Bundle thisBundle = FrameworkUtil.getBundle( HibernateUtil.class );
BundleContext context = thisBundle.getBundleContext();
ServiceReference sr = context.getServiceReference( SessionFactory.class.getName() );
sf = (SessionFactory) context.getService( sr );
}
return sf;
}
After many days of work and following many different leads I was able to solve the problem. The main idea was to store the database connection properties outside the hibernate.cfg.xml file which has to be inside the jar file for Hibernate OSGI to find it. In the contrary the properties file can be located anywhere you like. To accomplish this define a JNDI service using blueprint, then config the JNDI service on the hibernate.cfg.xml with the following tag:
<property name="connection.datasource">osgi:service/jdbc/mysqlds</property>
The code to define the JNDI service with blueprint is the following:
<bean id="dataSource"
class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
<property name="driverClass" value="${db.driverClass}"/>
<property name="url" value="${db.url}"/>
<property name="username" value="${db.username}"/>
<property name="password" value="${db.password}"/>
</bean>
<service interface="javax.sql.DataSource" ref="dataSource">
<service-properties>
<entry key="osgi.jndi.service.name" value="jdbc/mysqlds"/>
<entry key="datasource.name" value="MySqlDS"/>
</service-properties>
</service>
it is important to mention that I tried using many different DataSource classes which usually fail with a classnotfound error. The only that worked for me was SimpleDriverDataSource
Related
I have a spring based web application and in my application context xml file, I have defined a bean which has all the parameters to connect to database. As part of this bean, for one of the parameters, I have a password key, as shown in the below example and I wanted the value should come from a /vault/password file. This /vault/password is not part of the project/application. This /vault/password will be there in host machine by default.
What is the syntax in applicationContext.xml bean definition, to read a value from a file outside of application context.
<bean class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close" id="dataSource">
<property name="url" value="jdbc:postgresql://postgres:5432/" />
<property name="username" value="postgres" />
<property name="password" value="/vault/password" />
</bean>
Something like this is probably your best bet:
How to correctly override BasicDataSource for Spring and Hibernate
PROBLEM:
Now I need to provide custom data source based on server environment
(not config), for which I need to calculate driverClassName and url
fields based on some condition.
SOLUTION:
Create a factory (since you need to customize only the creation phase
of the object, you don't need to control the whole lifetime of it).
public class MyDataSourceFactory {
public DataSource createDataSource() {
BasicDataSource target = new BasicDataSource();
if (condition) {
target.setDriverClassName("com.mysql.jdbc.Driver");
target.setUrl("jdbc:mysql://localhost/test?relaxAutoCommit=true");
} else { ... }
return target;
}
}
In your case, your customization would do some I/O to set target.password.
I can persist new data, but I cannot do updates. There are no errors, just no transactions committing the changes. I'm assuming this has something to do with the way that I've set up transactions. I'm trying a bunch of relatively new (to me) set of technologies. Below are the details.
I'm using the following tools/technologies:
Wildfly 8 and Java 7 (which is what my hosting service uses)
Annotations, with minimal XML being the goal
Struts 2.3 (using the convention plugin)
Spring 3.2
Hibernate 4.3
JTA (with container managed transactions (CMT))
JPA 2 (with a Container Managed Persistence Context)
EJBs (I have a remote client app that runs htmlunit tests)
Three WAR files and one EJB JAR file deployed
SpringBeanAutowiringInterceptor to autowire the EJBs (could there be an error in here where transactions don't commit?)
beanRefContext.xml (required by SpringBeanAutowiringInterceptor)
<beans>
<bean
class="org.springframework.context.support.ClassPathXmlApplicationContext">
<constructor-arg value="classpath:campaignerContext.xml" />
</bean>
</beans>
campaignerContext.xml
<beans>
<context:component-scan base-package="..." />
<jee:jndi-lookup id="dataSource" jndi-name="jdbc/CampaignerDS"/>
<tx:annotation-driven/>
<tx:jta-transaction-manager/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="campaigner" />
</bean>
<bean id="ehCacheManager" class="net.sf.ehcache.CacheManager" factory-method="create">
<constructor-arg type="java.net.URL" value="classpath:/campaigner_ehcache.xml"/>
</bean>
</beans>
persistence.xml
<persistence>
<persistence-unit name="campaigner" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>java:/jdbc/CampaignerDS</jta-data-source>
<class>....UserRegistration</class>
...
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
<properties>
<property name="hibernate.transaction.jta.platform" value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform" />
</properties>
</persistence-unit>
</persistence>
SecurityServiceBean.java
#EnableTransactionManagement
#TransactionManagement(value = TransactionManagementType.CONTAINER)
#TransactionAttribute(value = TransactionAttributeType.REQUIRES_NEW)
#Stateless
#Interceptors(SpringBeanAutowiringInterceptor.class)
#DeclareRoles("Security Admin")
public class SecurityServiceBean extends AbstractCampaignerServiceImpl implements
SecurityServiceLocal, SecurityServiceRemote
{
#Override
#PermitAll
#Transactional(propagation = Propagation.REQUIRES_NEW)
public UserRegistration confirmRegistration(
String confirmationCode) throws ApplicationException
{
UserRegistration userRegistration = this.userRegistrationDAO
.find(new UserRegistrationQuery(null, confirmationCode)).uniqueResult(); // Should be attached now
...
userRegistration.setConfirmationDate(new Date());
userRegistration.setState(State.CONFIRMED);
userRegistration = this.userRegistrationDAO.saveOrUpdate(userRegistration);
...
}
}
UserRegistrationDAO.java
#Override
public UserRegistration saveOrUpdate(
UserRegistration obj) throws DAOException
{
log.debug("[saveOrUpdate] isJoinedToTransaction? "
+ (this.em.isJoinedToTransaction() ? "Y " : "N"));
try
{
if (obj.getId() == null)
{
this.em.persist(obj);
log.debug("[saveOrUpdate] called persist()");
return obj;
}
else
{
UserRegistration attached = this.em.merge(obj);
log.debug("[saveOrUpdate] called merge()");
return attached;
}
}
catch (PersistenceException e)
{
throw new DAOException("[saveOrUpdate] obj=" + obj.toString() + ",msg=" + e.getMessage(), e);
}
}
Are there any settings in Wildfly's standalone.xml that you need to see or that I should be setting?
BTW, this is incredibly annoying and frustrating. This should be an easy one-time setup that I can do and then forget about as I move on to creating my website, which should be where most of my time is spent. The lack of comprehensive documentation anywhere is AMAZING. Right now, development has been halted until this is solved
/rant
UPDATES
I tried switching to an XA data source, because some sites claimed that was necessary, but that didn't work (didn't think so but had to try). Also tried configuring emf with dataSource instead of persistenceUnitName as some other sites have. No joy.
I tried replacing the transactionManager with JpaTransactionManager, but that just led to this exception: A JTA EntityManager cannot use getTransaction()
The answer, thanks to M. Deinum, is that I was using the wrong #Transactional. I should have been using javax.transaction.Transactional but was using the Spring one instead. Note that the correct one will look like "#Transactional(TxType.REQUIRES_NEW)" instead of "#Transactional(propagation = Propagation.REQUIRES_NEW)"
I have been trying to access MySQL routines from my Spring project using SimpleJdbcDaoSupport.
I have a class called 'AdminSimpleMessageManager', which implements the interface 'AdminMessageManager'.
'AdminSimpleMessageManager' has an instance of the class 'AdminSimpleJdbcMessageDao', which implements the interface 'AdminMessageDao'.
AdminSimpleJdbcMessageDao has the following method:
public class AdminSimpleJdbcMessageDao extends SimpleJdbcDaoSupport implements AdminMessageDao {
public int addMessage(String from, String message) {
return getJdbcTemplate().queryForInt("call insert_contact_message(?, ?)", from, message);
}
}
I have included the following in my application context:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/OctagonDB"/>
</bean>
<bean id="adminMessageManager" class="Managers.AdminSimpleMessageManager">
<property name="adminMessageDao" ref="adminMessageDao"/>
</bean>
<bean id="adminMessageDao" class="Managers.dao.AdminSimpleJdbcMessageDao">
<property name="dataSource" ref="dataSource"/>
</bean>
but I feel there are a few important lines missing. I get the error
FAIL - Deployed application at context path /NewWebsite but context failed to start
among other things.
You need to include a MySQL JDBC driver in your classpath. Furthermore you should update the config of the driver class name to com.mysql.jdbc.Driver. org.gjt.mm.mysql.Driver is only retained for backwards compatibility.
However, since you seem to be loading the datasource through JNDI I guess the driver JAR should be in your container (which provides the datasource through JNDI) rather than in your app's WEB-INF/lib?
I want to place property place holders in the ehcache.xml file (like ${}) so that the values can be replaced from external properties file (.properties) at runtime.
Something like:
ehcache.xml (in classpath):
<defaultCache
maxElementsInMemory="20000"
eternal="false"
timeToIdleSeconds="${default_TTI}"
timeToLiveSeconds="86400"
overflowToDisk="true"
... />
ehcache.properties (outside of the war/classpath):
...
default_TTI=21600
...
The purpose is to be able to change the cache configuration without the need to rebuild the app. Spring's PropertyPlaceHolder will only work with Spring bean definiton for ehcache which I dont want (need to keep the ehcache.xml as a file)
There are similar posts here but nothing got me to solution. I've been searching for a week now!!
Im using Spring 2.5.6,Hibernate 3.2.6 and Ehcache 2.4.6
Any help or idea is greatly Appriciated!!
Thanks a lot,
Tripti.
As a workaroud solution you can set property values to system scope (System.setProperty(...)). EhCahe uses these properties to resolve placeholders during parsing its configuration file.
I got the solution finally! Thanks to braveterry for pointing me in that direction.
I used this at context startup:
Inputstream = new FileInputStream(new File("src/config/ehcache.xml").getAbsolutePath());
cacheManager = CacheManager.create(stream);
in conjuction with hibernate configuration:
<prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.SingletonEhCacheProvider</prop>
This creates a singleton CacheManager from ehcache.xml file outside the context classpath. I was doing this same earlier but was accidently creating another CacheManager before this one using the default ehcache.xml in the classpath.
Thanks,
Tripti.
svaor, I follow what you mean, I define a bean like this:
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="java.lang.System" />
<property name="targetMethod" value="setProperty" />
<property name="arguments">
<list>
<value>system.project_name</value>
<value>${system.project_name}</value>
</list>
</property>
</bean>
system.project_name define in system.properties file which locate in classpath
I also create a ehcache.xml in classpath, in ehcache.xml has the code like this:
<diskStore path="${java.io.tmpdir}/${system.project_name}/cache" />
but when I deploy my project, I find it cann't use the system.project_name define in system.properties, why?
If you just want to read the config in from disk at startup, you can do the following in EHCache 2.5:
InputStream fis =
new FileInputStream(new File("src/config/ehcache.xml").getAbsolutePath());
try
{
CacheManager manager = new CacheManager(fis);
}
finally
{
fis.close();
}
I have a spring context xml file with this
<context:property-placeholder location="classpath:cacheConfig.properties"/>
<bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="cacheManagerName" value="cacheName"/>
<property name="shared" value="false"/>
<property name="configLocation" value="classpath:cacheConfig.xml"/>
</bean>
the goal is to allow the customer to edit the properties file, like this
cache.maxMemoryElements="2000"
and then in the actual cacheConfig.xml file have this
<cache name="someCacheName"
maxElementsInMemory="${cache.maxMemoryElements}" ... />
so that items we do not want the customer to change are not exposed. Of course the above details are only partially detailed and NOT working. Currently I see this in the log file
Invocation of init method failed; nested exception is net.sf.ehcache.CacheException: Error configuring from input stream. Initial cause was null:149: Could not set attribute "maxElementsInMemory".
Thanks in advance...
Your example uses EhCacheManagerFactoryBean to expose a reference to the CacheManager, with caches defined in the external cacheConfig.xml file. As #ChssPly76 pointed out, Spring's property resolver only works within Spring's own bean definition files.
However, you don't have to define the individual caches in the external file, you can define them right within the Spring bean definition file, using EhCacheFactoryBean:
FactoryBean that creates a named
EHCache Cache instance... If the
specified named cache is not
configured in the cache configuration
descriptor, this FactoryBean will
construct an instance of a Cache with
the provided name and the specified
cache properties and add it to the
CacheManager for later retrieval.
In other words, if you use EhCacheFactoryBean to refer to a named cache that isn't already defined in cacheConfig.xml, then Spring will create and configure a new cache instance and register it with the CacheManager at runtime. That includes specifying things like maxElementsInMemory, and because this would be specified in the Spring bean definition file, you get full support of the property resolver:
<context:property-placeholder location="classpath:cacheConfig.properties"/>
<bean id="myCache" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager" ref="cacheManager"/>
<property name="maxElementsInMemory" value="${cache.maxMemoryElements}"/>
</bean>
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="shared" value="false"/>
<property name="configLocation" value="classpath:cacheConfig.xml"/>
</bean>
This is not how PropertyPlaceholderConfigurer works. It can be used to replace values within context, but not within arbitrary external files. And cacheConfig.xml is an external file - it's just being passed by Spring to EH Cache.
If you are using Maven or Ant, both offer the ability to do filtering of tokens in resource files.
For Maven, you could do something like
<cache name="someCacheName"
maxElementsInMemory="${cache.maxMemoryElements}" ... />
And in a filter file, or in the POM itself, have
cache.maxMemoryElements = 200
Resource Filtering in Maven: The Definitive Guide
With Ant, you do this with FilterSets and the <copy> task.
For anyone who needs to modify the diskstore path which cannot be set as the ehcache javadoc states that the diskstore parameter is ignored, you could create your own implementation of a EhCacheManagerFactoryBean, which allows you to inject the diskstore path; you basically need to intercept the creation of the CacheManager and modify the configuration passed along using your diskstore property, e.g.:
private String diskStorePath;
...getter/setter
public void afterPropertiesSet() throws IOException, CacheException {
if (this.shared) {
// Shared CacheManager singleton at the VM level.
if (this.configLocation != null) {
this.cacheManager = CacheManager.create(this.createConfig());
}
else {
this.cacheManager = CacheManager.create();
}
}
else {
// Independent CacheManager instance (the default).
if (this.configLocation != null) {
this.cacheManager = new CacheManager(this.createConfig());
}
else {
this.cacheManager = new CacheManager();
}
}
if (this.cacheManagerName != null) {
this.cacheManager.setName(this.cacheManagerName);
}
}
private Configuration createConfig() throws CacheException, IOException {
Configuration config = ConfigurationFactory.parseConfiguration(this.configLocation.getInputStream());
DiskStoreConfiguration diskStoreConfiguration = config.getDiskStoreConfiguration();
if (diskStoreConfiguration == null) {
DiskStoreConfiguration diskStoreConfigurationParameter = new DiskStoreConfiguration();
diskStoreConfigurationParameter.setPath(getDiskStorePath());
config.addDiskStore(diskStoreConfigurationParameter);
} else {
diskStoreConfiguration.setPath(getDiskStorePath());
}
return config;
}
The Spring config then looks like this:
<bean id="cacheManager" class="com.yourcompany.package.MyEhCacheManagerFactoryBean" depends-on="placeholderConfig">
<property name="diskStorePath" value="${diskstore.path}"/>
<property name="configLocation" value="classpath:ehcache.xml" />
</bean>