Issue while loading multiple Spring JPA context - spring

We are develpoing a application for fetching data from two separate databases[Mssql/Sybase].We are using Spring JPA (OpenJPA implementation) to interact with both databases. We used two different context files(Mssqlcontext.java and SybaseContext.java) for each DB. We have set separate profile name in context files(MsSqlProfile/SybaseProfile). We needs to conditionally load the context files based on our configuration. But the details of which database is configured is specified in an seperate configuration xml file. XML file is read as part of a bean. We are loading context using #import annotation. JPA expects to give correct DB details while loading a context. But the context is imported before reading the configuration file. So we can't provide the correct database details.
The main problem that are trying to solve is that the Spring application should not crash if any of the database is not configured.
We tried to load the configuration bean before importing the context by implementing the following
Condition
ImportSelector
DeferredImportSelector
Ordered
However these are not working as expected.
Sample code
public class SampleServiceInitializer implements WebApplicationInitializer
{
/**
* Register the Spring configuration.
*/
public void onStartup(ServletContext container) throws ServletException
{
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
....
....
ctx.register(SampleServiceConfiguration.class);
....
....
}
}
#Import(SampleControllerConfiguration.class)
public class SampleServiceConfiguration
{
#Bean(name = configurationBean)
#Scope("singleton")
public ConfigRegistration getConfiguration()
{
ConfigRegistration config = new ConfigRegistration();
config.init();
// Here we read the configurations and set the profile name(SyabseProfile/MssqlProfile)
return config;
}
}
#Import({ SampleDataSourceConfiguration.class, SampleRequestorConfiguration.class })
public class SampleControllerConfiguration
{
....
....
}
#Import({ MSSqlContext.class, SybaseContext.class })
public class SampleDataSourceConfiguration
{
....
....
}
#Configuration
#Profile(MsSqlProfile)
....
....
public class MSSqlContext
{
....
....
}
#Configuration
#Profile(SybaseProfile)
....
....
public class SybaseContext
{
....
....
}
In the above sample code MSSqlContext and SybaseContext is initialized before the configurationBean.

Related

Spring - Create scheudled tasks from external files

I have a spring boot application that reads configuration files from storage.
I want that for each file - a scheduled task will be created.
The files are read and stored into a Pojo MyFileData and i have a bean that returns List<MyFileData>
I have read about SchedulingConfigurer but I don't understand how i can get the bean value inside the configureTasks method.
#Configuration
public class FirstConfigFile {
#Bean
public List<MyFileData> myFileDataList() {
List<MyFileData> myConfigFiles = new ArrayList();
// read from storage
return myConfigFiles;
}
}
#Configuration
public class SecondConfigFile implements SchedulingConfigurer {
#Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
// how do i get the myFileDataList bean?
for(MyFileData fd : myFileDataList) {
// create scheduled tasks and regiester them in the taskRegistrar
}
}
}
Note: I prefer to keep the #Configuration classes separate.
You can #Autowired that List as it is declared as #Bean.

Using context beans within a Condition or a ConfigurationCondition

I wish to use a org.springframework.context.annotation.Condition interface to disable/enable at startup some of my #Configuration classes. Example below:
public class Condition implements ConfigurationCondition {
#Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//Gets the configuration manager from the context
RapidConfDocConfiguration.DocConf docConf = context.getBeanFactory().getBean(DocConf.class);
return docConf.isEnabled();
}
}
#Configuration
public class ConfDocConfiguration {
#Bean
public DocConf docConf() {
return new DocConf(true);
}
}
#Configuration
#Import(ConfDocConfiguration.class)
#Conditional({Condition.class})
public class RapidSwaggerConfiguration {
//Some configurations
}
The problem i have here is that the Condition is executed before that any of the context is instantiated and then the 'DocConf' is not yet present. The Condition works well if i read an environment variable or something like that.
So, is it possible to use this kind of condition based on a spring bean of the context ?
This is not possible because your DocConf class is not loaded as a Configuration, #Bean annotated beans are created after all configuration is done.
For this to work, your DocConf class would have to be added to the context as a Spring configuration, so including it via #Bean from a different configuration cannot work, because non-configuration Beans are only created after the configuration phase.
Consider this article: http://www.javarticles.com/2016/01/spring-configuration-condition-example.html
Another example at http://javapapers.com/spring/spring-conditional-annotation/

Inject test beans into main method

I'm using JavaConfig to manage and wire Spring beans into my Java app. The Java application is a main method - and basically runs as a batch job, invoked via a bash file. Is there a way that I can use a different (test) config in my main method?
public static void main(String[] args) {
final ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
// do Stuff
}
I have used the following annotations successfully before in my test classes:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = { TestConfig.class })
, but this does not work for "main" applications. Short of passing in the Spring context to use as an argument, not sure what I can do here. Thanks
You should be able to use profiles in your actual config class to do what you want as well.
By setting the desired Profile you can "inject" the different beans you want.
Your ApplicationConfig might look like:
#Configuration
#Import({
JndiDataConfig.class,
TestDataConfig.class,
)
public class ApplicationConfig {
...
where TestDataConfig looks (in part) like:
#Configuration
#Profile("test")
public class TestDataConfig {
#Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.HSQL)
.addScript("classpath:com/bank/config/sql/schema.sql")
.addScript("classpath:com/bank/config/sql/test-data.sql")
.build();
}
}
and where JndiDataConfig looks like:
#Configuration
#Profile("production")
public class JndiDataConfig {
#Bean
public DataSource dataSource() throws Exception {
Context ctx = new InitialContext();
return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
}
}

Best way to test JPA Spring 3.1

I have written several JPA Repositories, Services and support classes for my Spring 3.1.1/JPA/Hibernate 4 web app. However, I really want to write some unit and integration tests for it (I know, you are supposed to write those first). I am using JavaConfig rather than XML, so I am wondering the best way to test. Here is the particular problem I am trying to solve:
I have a #Configuration that declares DataSource, JpaTransactionManager, LocalContainerEntityManagerFactoryBean, and all my respositories. Obviously I don't want to start all that up for an integration test, so I thought I could use the EmbeddedDatabase and H2 to create an in memory database, populate with values, and then use my Repositories against it. However, the documentation I have seen hasn't helped me put this together. I have this:
#RunWith( SpringJUnit4ClassRunner.class )
public class TestMenuService {
private EmbeddedDatabase database;
#Autowired
private MenuRepository menuRepository;
#Before
public void setUp() throws Exception {
database = new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).setName("myschema")
.addScript("classpath:schema.sql").build();
menuRepository = new MenuRepository();
Assert.assertNotNull(database);
}
But the menuRepository does not get instantiated, so I tried creating a test version of my #Configuration
#Configuration } )
#ComponentScan( basePackages = { "com.mycompany.service"} )
#EnableTransactionManagement
#ImportResource( "classpath:applicationContext.xml" )
#PropertySource( "classpath:test-application.properties" )
public class TestEdmConfiguration {
#Bean
MenuRepository menuRepository() {
return new MenuRepository();
}
My test-applicationContext.xml
<jpa:repositories base-package="com.mycompany.servce.repository"/>
My test-application.properties:
db.driver=org.h2.Driver
db.username=sa
db.password=
db.url=jdbc:h2:mem:myschema
hibernate.dialect=org.hibernate.dialect.H2Dialect
hibernate.format_sql=true
hibernate.hbm2ddl.auto=create
hibernate.ejb.naming_strategy=org.hibernate.cfg.ImprovedNamingStrategy
hibernate.show_sql=true
But this requires that I create all the datasources, etc mentioned above. It seems like I am just duplicating all the support beans for this one.
Is there a way to have the reposository and embeddeddatabase isolated to my test without all the other dependencies?
If you want to test your repository in a full integration test I would image that you need everything else to be setup i.e. EntityManagerFactory, PlatformTransactionManager etc.
Since you are using Spring 3.1 I would suggest that you achieve this using bean profiles.
I would create two profiles one for tests and one for the application, each of which supplies a datasource.
#Configuration
#Profile("test")
public class EmbeddedDataSource {
#Bean
public DataSource dataSource() {
// Return a H2 datasource
}
}
#Configuration
#Profile("application")
public class ApplicationDataSource {
#Bean
public DataSource dataSource() {
// Return a normal datasource
}
}
The you can create a test which starts up the spring context as follows:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = { MyConfigClass.class })
#ActiveProfiles(profiles = {"test"})
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class TestRepository {
}
In here you can specify the profiles where are active for the test.

Convert Spring bean configuration into XML configuration

i am working on BIRT reporting tool. which is need to called by spring MVC.
i got one example from spring which is here. in this example, configuration is done via bean. can anyone help me convert this configuration in to xml based configuration ?
#EnableWebMvc
#ComponentScan({ "org.eclipse.birt.spring.core","org.eclipse.birt.spring.example" })
#Configuration
public class BirtWebConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/reports").setViewName("birtView");
}
#Bean
public BirtView birtView() {
BirtView bv = new BirtView();
// bv.setReportFormatRequestParameter("ReportFormat");
// bv.setReportNameRequestParameter("ReportName");
bv.setBirtEngine(this.engine().getObject());
return bv;
}
#Bean
public BeanNameViewResolver beanNameResolver() {
BeanNameViewResolver br = new BeanNameViewResolver();
return br;
}
#Bean
protected BirtEngineFactory engine() {
BirtEngineFactory factory = new BirtEngineFactory();
return factory;
}
}
I wants a similar configuration in xml file.
There's really no tool for extracting Spring annotations to Spring bean context xml file. You'll have to do it by hand, shouldn't be too hard as all the Spring annotations functionality can be duplicated into Spring context xml tags.
if you want to use spingmvc, so no need the configuration files.
my solution is that in Birt Script i call the impl java file like this :
sampleService = new Packages.com.example.warlock.service.SampleServiceImpl();
pojo = new Packages.com.example.warlock.entity.Sample();
iterator = sampleService.getSamples().iterator();
because my SampleService is a interface and SampleServiceImpl is impl java, the two java file are not config as #Bean.
At first i want to get the data from ModelMap but failed, so i skip the controller and straight to call Service, then final call the DAO to get the Data from DB

Resources