Linking Spring project to MySQl database - java

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?

Related

Liquibase with Spring Boot and multiple schemas, how to specify execution order

We have an data-migration job which needs to initialize schemas A and B, in that order. We handle multiple schemas by defining multiple SpringLiquibase, one for each schema, each with its own datasource and its own master changeset. (Note, normally in Spring Boot you wouldn't need to define a SpringLiquibase, because it would detect a single datasource and auto-configure the SpringLiquibase for you with that datasource.)
The execution order seems to vary depending whether the job is run locally within the IDE, or bundled as a single-JAR Spring Boot app.
How can we ensure that the two executions of liquibase happen in the order we want?
(Why the order is important: A contains some tables, while B contains views that reference tables in A. We have to make sure that we grant select on A.* to B before attempting to create view B.some_view (...) as select ... from A.xyz, otherwise the creation of B fails due to insufficient privileges.)
After some scratching of heads and digging into the source code, it turns out to be extremely simple.
SpringLiquibase implements InitializingBean and executes the Liquibase update within the InitializingBean.afterPropertiesSet() method.
Spring calls this method on each bean, one by one, after finishing initializing each one.
So to force a particular order, you need to force the order in which the beans are defined in the Spring context. And the easiest way to do this is with the #DependsOn annotation.
So we put in place something like:
#Bean
public SpringLiquibase liquibaseA(
#Qualifier("dataSourceA") DataSource dataSource,
#Qualifier("liquibasePropertiesA") LiquibaseProperties liquibaseProperties
) {
return instantiateSpringLiquibase(dataSource, liquibaseProperties);
}
#Bean
#DependsOn("liquibaseA")
public SpringLiquibase liquibaseB(
#Qualifier("dataSourceB") DataSource dataSource,
#Qualifier("liquibasePropertiesB") LiquibaseProperties liquibaseProperties
) {
return instantiateSpringLiquibase(dataSource, liquibaseProperties);
}
private SpringLiquibase instantiateSpringLiquibase(DataSource dataSource, LiquibaseProperties liquibaseProperties) {
// set the datasource from dataSource and everything else from liquibaseProperties
}
This is not for spring boot but if you manage your migrations via the change logs this workaround will help. This assumes you have different data sources for different schemas.
<bean id="liquibase1" class="liquibase.integration.spring.SpringLiquibase">
<property name="dataSource" ref="dataSource1" />
<property name="changeLog" value="classpath:db1-changelog1.xml" />
</bean>
<bean id="liquibase2" depends-on="liquibase1" class="liquibase.integration.spring.SpringLiquibase">
<property name="dataSource" ref="dataSource2" />
<property name="changeLog" value="classpath:db2-changelog1.xml" />
</bean>
<bean id="liquibase3" depends-on="liquibase2" class="liquibase.integration.spring.SpringLiquibase">
<property name="dataSource" ref="dataSource1" />
<property name="changeLog" value="classpath:db1-changelog2.xml" />
</bean>
<bean id="liquibase4" depends-on="liquibase3" class="liquibase.integration.spring.SpringLiquibase">
<property name="dataSource" ref="dataSource2" />
<property name="changeLog" value="classpath:db2-changelog2.xml" />
</bean>

Populate a datasource during the start of the spring application

I want to run some part of the code to populate the database with dummy data every time the server starts. I use Tomcat as my servlet container. My application is created using Spring. Is there a hook where I can run my code to populate the db just after my application is started?
You have two different alternatives.
The first one is using Spring's DataSourceInitializer. You can pass your initialisation query as a parameter and it executes that query. You can execute any command that you like.
Example:
<bean id="dbInitializer" class="org.springframework.jdbc.datasource.init.DataSourceInitializer">
<property name="dataSource" ref="myDataSourceRef"/>
<property name="enabled" value="true"/>
<property name="databasePopulator">
<bean class="org.springframework.jdbc.datasource.init.ResourceDatabasePopulator">
<property name="continueOnError" value="true"/>
<property name="ignoreFailedDrops" value="true"/>
<property name="sqlScriptEncoding" value="UTF-8"/>
<property name="scripts">
<array>
<value type="org.springframework.core.io.Resource">init.sql</value>
</array>
</property>
</bean>
</property>
</bean>
The second alternative is implementing a Spring ApplicationListener. Populate each datum from that listener to your database manually. It is a little harder to achieve.
Example:
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
public class ApplicationListenerBean implements ApplicationListener {
#Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ContextRefreshedEvent) {
ApplicationContext applicationContext = ((ContextRefreshedEvent) event).getApplicationContext();
// now you can do applicationContext.getBean(...)
// ...
}
}
}
This bean must be initialised by Spring. You can either define it in your applicationContext.xml or in your configuration class.
By the way, you can always listen for your ServletContext status by using a ServletContextListener. But if you are using Spring, there are easier methods.
You can use Liquibase, and if you're using Spring Boot all you have to do is add liquibase-core to your classpath, via maven or whatever build tool you're using is. Spring Boot uses YAML files by default. Spring Boot will then run Liquibase on every application startup.

Creating a different instance of an Object with scope prototype in OSGi using Spring

It is a complicated problem so I will explain it as clear as I can. I have three OSGi bundles A, B, C deployed into Apache Karaf. I also have a security bundle which is used by those A, B, C bundles.
Each A, B and C bundles contains this:
<osgi:reference id="basicAuthHandlerFactory" interface="com.groupgti.security.handler.basicauth.BasicAuthHandlerFactory"/>
<bean id="securityHandler" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="basicAuthHandlerFactory"/>
<property name="targetMethod" value="createSecurityHandler"/>
<property name="arguments">
<list>
<value type="java.lang.String">A.realm</value> <!-- The realm is depending on a bundle, A.realm, B.realm, C.realm -->
</list>
</property>
</bean>
Spring code snippet to get the security handler from security bundle. This handler in security bundle is exposed as an OSGi service and created in the security bundle like this:
<bean id="securityHandler" class="org.eclipse.jetty.security.ConstraintSecurityHandler" scope="prototype">
<property name="authenticator">
<bean class="org.eclipse.jetty.security.authentication.BasicAuthenticator"/>
</property>
<property name="constraintMappings">
<list>
<ref bean="constraintMapping"/>
</list>
</property>
<property name="strict" value="false"/>
<property name="identityService" ref="identityService"/>
</bean>
<bean id="basicAuthSecurityHandler" class="com.groupgti.security.handler.basicauth.BasicAuthFactoryHandlerImpl"/>
<osgi:service ref="basicAuthSecurityHandler" interface="com.groupgti.security.handler.basicauth.BasicAuthHandlerFactory"/>
BasicAuthFactoryHandlerImpl#createSecurityHandler(String realm) is used to create the different instance of the security handler for each bundle. The realm is passed by the bundle when createSecurityHandler method is invoked by Spring MethodInvokingFactoryBean as showed in the above code.
The securityHandler Spring bean has a scope prototype, in which case when every call to the method getBean is called this should return a newly created object.
The realm I am setting for security handler is like this:
public class BasicAuthFactoryHandlerImpl implements BeanFactoryAware, BasicAuthHandlerFactory {
private static final Logger LOGGER = LoggerFactory.getLogger(BasicAuthFactoryHandlerImpl.class);
private BeanFactory factory;
#Override
public ConstraintSecurityHandler createSecurityHandler(String realm) {
ConstraintSecurityHandler handler = (ConstraintSecurityHandler) factory.getBean("securityHandler");
handler.setUserRealm(realm);
LOGGER.debug("Security handler created. Got realm: {}", realm);
return handler;
}
#Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.factory = beanFactory;
}
}
Handlers for each bundle gets created, everything is fine. But the problem is that the realm for all bundles is somehow the same realm passed from the first started bundle. I am sure I am passing different realms in each Spring configuration in different bundles, but the realm is always from the first started bundle and it is not working correctly.
Does anybody have an idea where might be the problem?
The problem is that you get the single "securityHandler" from the beanFactory. So there is only one shared instance. Inside the createSecurityHandler you should create a new object and return it.
I was able to figure out the problem why the same instance is shared across applications. All my bundles A, B and C, used this:
<httpj:engine-factory bus="cxf">
<httpj:engine port="8020">
<httpj:threadingParameters minThreads="5" maxThreads="15"/>
<httpj:handlers>
<ref bean="securityHandler"/>
<ref bean="ipFilteringHandler"/>
</httpj:handlers>
<httpj:sessionSupport>true</httpj:sessionSupport>
</httpj:engine>
</httpj:engine-factory>
to create the security handlers and for all of them Jetty used the same port 8020. And it wasn't able to handle the different handlers on the same port. If I changed the the ports to be all different, everything worked. But that was not the solution for me. The solution was to make one realm to be used by all bundles.
AFAIR the problem here is more the way spring does the proxying. Cause the proxying is done for the service Reference and not the service. You probably need to configure it correctly for using the right proxying.
I think something like the following will probably help:
ServiceReference nativeReference = ((ServiceReferenceProxy)serviceReference).getTargetServiceReference()

Programmatically loading Entity classes with JPA 2.0?

With Hibernate you can load your Entity classes as:
sessionFactory = new AnnotationConfiguration()
.addPackage("test.animals")
.addAnnotatedClass(Flight.class)
.addAnnotatedClass(Sky.class)
.addAnnotatedClass(Person.class)
.addAnnotatedClass(Dog.class);
Is there a way to do the same thing - programmatically loading your Entity classes - in a JPA 2.0 compliant way?
The reason for this question is because I'd like to dynamically load my Entity classes, thus not necessarily programmatically.
With the help of Spring I did this in a JPA compliant way.
My "persistence.xml" looks empty, with no entities listed within the <persistence-unit> element.
I then wrote a class that implemented PersistenceUnitPostProcessor like so:
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.MappedSuperclass;
import org.reflections.Reflections;
import org.reflections.scanners.TypeAnnotationsScanner;
import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo;
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;
public class ReflectionsPersistenceUnitPostProcessor implements PersistenceUnitPostProcessor {
private String reflectionsRoot;
private Logger log = LoggerFactory.getLogger(ReflectionsPersistenceUnitPostProcessor.class);
#Override
public void postProcessPersistenceUnitInfo(MutablePersistenceUnitInfo pui) {
Reflections r = new Reflections(this.reflectionsRoot, new TypeAnnotationsScanner());
Set<String> entityClasses = r.getStore().getTypesAnnotatedWith(Entity.class.getName());
Set<String> mappedSuperClasses = r.getStore().getTypesAnnotatedWith(MappedSuperclass.class.getName());
for (String clzz : mappedSuperClasses)
{
pui.addManagedClassName(clzz);
}
for (String clzz : entityClasses)
{
pui.addManagedClassName(clzz);
}
}
public String getReflectionsRoot() {
return reflectionsRoot;
}
public void setReflectionsRoot(String reflectionsRoot) {
this.reflectionsRoot = reflectionsRoot;
}
}
Then I adjusted my spring context xml like this:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="false" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
</bean>
</property>
<property name="persistenceUnitName" value="GenericPersistenceUnit"/>
<property name="persistenceXmlLocation" value="classpath:META-INF/persistence.xml"/>
<property name="persistenceUnitPostProcessors">
<list>
<bean class="com.austinmichael.core.repository.ReflectionsPersistenceUnitPostProcessor">
<property name="reflectionsRoot" value="com.austinmichael"/>
</bean>
</list>
</property>
</bean>
Note the registration of the ReflectionsPersistenceUnitPostProcessor in the persistenceUnitPostProcessors setting.
And that's it. Every class with a JPA Entity or MappedSuperclass annotation on the classpath is added to the classpath. I had to give reflections the prefix of a package name to scan through which is why com.austinmichael is there at all. You could register a second ReflectionsPersistenceUnitPostProcessor with a different package name prefix if you want if your entities don't share a common package name prefix.
But, this is now JPAVendor agnostic.
Is there a way to do the same thing - programmatically loading your Entity classes - in a JPA 2.0 compliant way?
No, this is not supported by JPA so you'll have to do this in a provider specific way. James Sutherland described the process for EclipseLink in this thread like this:
You can access the EclipseLink ServerSession from the EntityManagerFactoryImpl (getServerSession()), and use its' addDescriptor(ClassDescriptor) or addDescriptors() API to add EclipseLink ClassDescriptor. You will need to build the ClassDescriptor meta-data objects directly yourself (or use the Mapping Workbench to create them), as loading from JPA annotations or orm.xml would be more difficult.
Also have a look at this more recent thread for more code sample (the API looks like a bit verbose).
References
Re: [eclipselink-users] Close to get it. Just a little help
Re: JPA: adding entities to EntityManagerFactory programmatically
I don't think there is such option - JPA supports scanning the classpath for entities or explicitly listing the entity classes in the persistence.xml. Since you're using hibernate as the persistence provider however you can always resort to hibernate code. Have a look at the HibernateEntityManager and HibernateEntityManagerFactory classes. You can cast entity manager factories and entity managers to them and do the usual hibernate stuff.

Import Spring config file based on property in .properties file

In my Spring xml configuration I'm trying to get something like this to work:
<beans>
<import resource="${file.to.import}" />
<!-- Other bean definitions -->
</beans>
I want to decide which file to import based on a property in a properties file.
I know that I can use a System property, but I can't add a property to the JVM at startup.
Note: The PropertyPlaceHolderConfigurer will not work. Imports are resolved before any BeanFactoryPostProcessors are run. The import element can only resolve System.properties.
Does anyone have a simple solution to this? I don't want to start subclassing framework classes and so on...
Thanks
This is, unfortunately, a lot harder than it should be. In my application I accomplished this by doing the following:
A small, "bootstrap" context that is responsible for loading a PropertyPlaceholderConfigurer bean and another bean that is responsible for bootstrapping the application context.
The 2nd bean mentioned above takes as input the "real" spring context files to load. I have my spring context files organized so that the configurable part is well known and in the same place. For example, I might have 3 config files: one.onpremise.xml, one.hosted.xml, one.multitenant.xml. The bean programmatically loads these context files into the current application context.
This works because the context files are specified as input the the bean responsible for loading them. It won't work if you just try to do an import, as you mentioned, but this has the same effect with slightly more work. The bootstrap class looks something like this:
public class Bootstrapper implements ApplicationContextAware, InitializingBean {
private WebApplicationContext context;
private String[] configLocations;
private String[] testConfigLocations;
private boolean loadTestConfigurations;
public void setConfigLocations(final String[] configLocations) {
this.configLocations = configLocations;
}
public void setTestConfigLocations(final String[] testConfigLocations) {
this.testConfigLocations = testConfigLocations;
}
public void setLoadTestConfigurations(final boolean loadTestConfigurations) {
this.loadTestConfigurations = loadTestConfigurations;
}
#Override
public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
context = (WebApplicationContext) applicationContext;
}
#Override
public void afterPropertiesSet() throws Exception {
String[] configsToLoad = configLocations;
if (loadTestConfigurations) {
configsToLoad = new String[configLocations.length + testConfigLocations.length];
arraycopy(configLocations, 0, configsToLoad, 0, configLocations.length);
arraycopy(testConfigLocations, 0, configsToLoad, configLocations.length, testConfigLocations.length);
}
context.setConfigLocations(configsToLoad);
context.refresh();
}
}
Basically, get the application context, set its config locations, and tell it to refresh itself. This works perfectly in my application.
Hope this helps.
For the Spring 2.5 and 3.0, I have a similar solution to louis, however I've just read about 3.1's upcoming feature: property management, which sounds great too.
There is an old issue on the Spring JIRA for adding properties placeholder support for import (SPR-1358) that was resolved as "Won't Fix", but there has since been a proposed solution using an EagerPropertyPlaceholderConfigurer.
I've been lobbying to have SPR-1358 reopened, but no response so far. Perhaps if others added their use cases to the issue comments that would help raise awareness.
Why not:
read your properties file on startup
that will determine which Spring config to load
whichever Spring config is loaded sets specific stuff, then loads a common Spring config
so you're effectively inverting your current proposed solution.
Add something similar to the following:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreResourceNotFound"><value>true</value></property>
<property name="locations">
<list>
<value>classpath:propertyfile.properties</value>
</list>
</property>
</bean>
If what you want is to specify the imported XML file name outside applicationContext.xml so that you could replace applicationContext.xml without losing the configuration of the imported XML file path, you can just add an intermediate Spring beans XML file, say, confSelector.xml, so that applicationContext.xml imports confSelector.xml and confSelector.xml only contains an <import> element that refers to the suitable custom beans XML file.
Another means that might be of use are XML entities (defined by adding <!ENTITY ... > elements into the DTD declaration at the beginning of XML). These allow importing XML fragments from other files and provide "property placeholder"-like functionality for any XML file.
Neither of these solutions allows you to have the configuration file in Java's .properties format, though.
André Schuster's answer, which I bumped, helped me solve a very similar issue I was having in wanting to find a different expression of properties depending on whether I was running on my own host, by Jenkins on our build host or in "real" deployment. I did this:
<context:property-placeholder location="file:///etc/myplace/database.properties" />
followed later by
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>WEB-INF/classes/resources/database.properties</value>
...
</list>
</property>
</bean>
which solved my problem because on my development host, I put a link to my own copy of database.properties in /etc/myplace/database.properties, and a slightly different one on the server running Jenkins. In real deployment, no such file is found, so Spring falls back on the "real" one in resources in my class files subdirectory. If the properties in question have already been specified by the file on /etc/myplace/database.properties, then (fortunately) they aren't redefined by the local file.
Another workaround which does not rely on system properties is to load the properties of all the files using a different PropertyPlaceholderConfigurer for each file and define a different placeholderPrefix for each of them.
That placeholderprefix being configured by the initial property file.
Define the first property file: (containing either first or second)
global.properties
fileToUse=first
Define the files containing a property that can be switched depending on the property defined just above:
first.properties
aProperty=propertyContentOfFirst
second.properties
aProperty=propertyContentOfSecond
Then define the place holders for all the files:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:global.properties</value>
</list>
</property>
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="placeholderPrefix" value="first{" />
<property name="locations">
<list>
<value>classpath:first.properties</value>
</list>
</property>
</bean>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="placeholderPrefix" value="second{" />
<property name="locations">
<list>
<value>classpath:second.properties</value>
</list>
</property>
</bean>
Use the property defined in global to identify the resource to use from the other file:
${fileToUse}{aProperty}
If I add the JVM argument below and have the file myApplicationContext.dev.xml, spring does load
-DmyEnvironment=dev
<context:property-placeholder />
<import resource="classpath:/resources/spring/myApplicationContext.${myEnvironment}.xml"/>
I'm using Spring 3 and load a properties like that:
<context:property-placeholder location="/WEB-INF/my.properties" />

Categories