factory and dao to support some database with spring - database

Currently we have an application who use spring who support mysql.
Some people prefer to use Oracle.
So i search a way with spring to have an abstract factory with a factory for every database and each one have a dao.
How to put the glue between all this component?
How the component know the datasource who need to be used?
Is there some good pratice with spring to do this?

Not clear what exactly is your problem, but Spring profiles are answer to all of them. First you need to define two DataSources for each supported database:
<bean id="oracleDataSource" class="..." profile="oracle">
<!-- -->
</bean>
<bean id="mysqlDataSource" class="..." profile="mysql">
<!-- -->
</bean>
Note the profile attribute. Actually you will probably get away with simply parametrizing one data source yo use different JDBC URL and driver, but doesn't matter.
Now you define two versions of each DAO: one for Oracle and one for MySQL:
interface MonkeyDao {
//...
}
#Repository
#Profile("oracle")
class OracleMonkeyDao implements MonkeyDao {
//...
}
#Repository
#Profile("mysql")
class MySqlMonkeyDao implements MonkeyDao {
//...
}
As you can see you have two beans defined implementing the same interface. If you do it without profiles and then autowire them:
#Resource
private MonkeyDao monkeyDao;
Spring startup will fail due to unresolved dependency. But if you enable one of the profiles (either mysql or oracle) Spring will only instantiate and create bean for matching profile.

Related

Apache Karaf datasource as a service versus in blueprint

I am a bit confused about working with Blueprint camel and Apache Karaf. In fact, when I was developping my route, I was using this to connect to my mssql database :
<bean id="dbcp" destroy-method="close" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
<property name="url" value="jdbc:sqlserver://server\instance;databaseName=xxx;" />
<property name="username" value="xxxx" />
<property name="password" value="xxx" />
</bean>
This was working flawlessly and then I wanted to export it into Apache Karaf. I did so and ran into a lot of trouble because of the sqlserver driver not being found. So I tried to handle this another way by exposing the DataSource as a service on Apache Karaf. This works and I get a hold of the reference like so in my blueprint:
<reference id="dbcp" interface="javax.sql.DataSource" filter="(osgi.jndi.service.name=Name)" availability="mandatory" />
Now this works but I don't exactly know what this does behind the scenes. I've read about services and references and often to make my first example work, people use a service call and then use it in the bean.
Is there a right and a wrong way? I've read on top of that, that we should a connection pool but I have only seen an example of this in the first approach (1st code sample). I guess it does the same when done with the DataSource as a service since I can call it from multiple bundles.
Thanks for regarding, best regards
In Apache Karaf versions 4.2.x - 4.4.x it's generally a good practice to use OSGi Services to share DataSource type objects. This makes your bundles more loosely coupled and when making changes to connection parameters you'll only need to change them for the service instead of having to reconfigure every bundle that uses the said DataSource.
You can also create your own shared resources and expose them as services using blueprints, declarative service annotations or the "hard way" using activator and bundle context.
I also recommend to checkout features pax-jdbc-config and pax-jms-config features as they allow you to create DataSource and ConnectionFactory type services from config files. These look for config files using org.ops4j.datasource org.ops4j.datasource prefixes in their name e.g org.ops4j.datasource-Example.cfg
Only downside for using services is that they're specific to Karaf and OSGi so if you ever need to move your integrations to non-osgi environment you'll have to figure out another way to inject data sources to your integrations.
[edit]
With shared resources I mean resources you might want to access from multiple bundles. These can be anything from objects that contain shared data, connection objects for cloud blob storages, data access objects, slack or discord bots, services for sending mails etc.
You can publish new services using blueprints from beans using service tag. Below is example from OSGi R7 Specification
<blueprint>
<service id="echoService"
interface="com.acme.Echo" ref="echo"/>
<bean id="echo" class="com.acme.EchoImpl">
<property name="message" value="Echo: "/>
</bean>
</blueprint>
public interface Echo {
public String echo(String m);
}
public class EchoImpl implements Echo {
String message;
public void setMessage(String m) {
this.message= m;
}
public void echo(String s) { return message + s; }
}
With OSGi Declarative services (DS) / Service Component Runtime (SCR) annotations you can publish new services with java.
#Component
public class EchoImpl implements Echo {
String message;
public void setMessage(String m) {
this.message= m;
}
public void echo(String s) { return message + s; }
}
Another example can be found from Official Karaf examples in github.

#EnableJpaRepositories annotation disables data.sql initialization script

My Spring Boot (v2.3.4) based application uses my custom library containing core entities and business logic. To use entities and repositories from this library I had to use #EnableJpaRepositories and #EntityScan annotations with proper packages provided.
I also wanted to initialize database with some required data (let's say the configuration) during application startup. I found that Spring Boot allows to use data.sql or data-${platform}.sql files to achieve that.
Long story short when using #EnableJpaRepositories annotation the data.sql script is not executed.
I did some digging in the code and found that when #EnableJpaRepositories annotation is not used then entityManagerFactory bean is of org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean type. This bean uses org.springframework.boot.autoconfigure.orm.jpa.DataSourceInitializedPublisher bean post processor, which fires org.springframework.boot.autoconfigure.jdbc.DataSourceSchemaCreatedEvent event indicating the schema has been created. Class, which listens for this event is org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerInvoker. This listener invokes initSchema() method from org.springframework.boot.autoconfigure.jdbc.DataSourceInitializer class. This method is responsible for whole initialization using data.sql script.
It looks like setting #EnableJpaRepositories annotation creates instance of different class for entityManagerFactory bean, which does not support this simple initialization.
My basic question is then how to make it all work with #EnableJpaRepositories annotation. I can always use Hibernate's import.sql file (which works fine) but I'm also trying to understand what exactly is going on under the hood I how can I control it.
UPDATE 1 28.09.2021
I did further investigation and #EnableJpaRepositories annotation does not change the instance type of entityManagerFactory but it causes silent exception (?) when creating org.springframework.scheduling.annotation.ProxyAsyncConfiguration bean (during creation of org.springframework.context.annotation.internalAsyncAnnotationProcessor bean). It looks like everything is related to #EnableAsync annotation, which I'm also using but didn't know it might be related. But it is - removing it makes the initialization work even with #EnableJpaRepositories.
UPDATE 2 28.09.2021
I've found full explanation for my issue. There are 4 conditions, which must be met to reproduce the issue:
#EnableJpaRepositories annotation in application configuration
#EnableAsync annotation in application configuration
Configuration implements AsyncConfigurer interface
Autowired any JpaRepository repository or any other bean which injects repository
Enabling asynchronous execution and implementing AsyncConfigurer makes the whole configuration to be instantiated before regular beans. Because Spring has to inject repository, it needs to instantiate entityManagerFactory bean too. Spring prints thenINFO level logs like below:
Bean 'entityManagerFactoryBuilder' of type [org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
One of not eligible BeanPostProcessors is DataSourceInitializedPublisher responsible for firing DataSourceSchemaCreatedEvent event. Without that event, data-${platform}.sql script won't be processed at all.
I'm not sure what is the role of #EnableJpaRepositories in that process but without it the problem does not occur.
Example
Minimal code to reproduce the issue (data.sql located in src/main/resources):
#Entity
public FileStore {
...
}
public interface FileStoreRepository extends extends JpaRepository<FileStore, Long> {
}
#Configuration
#EnableAsync
#EnableJpaRepositories
public class Configuration implements AsyncConfigurer {
#Autowired
private FileStoreRepository fileStoreRepository;
...
}
Solutions
There are two solutions I'm aware of:
Move AsyncConfigurer along with its overrided methods and #EnableAsync annotation to separate configuration class
Use #Lazy annotation on autowired bean like below:
#Lazy
#Autowired
private FileStoreRepository fileStoreRepository;
Similar problem was pointed by #Allen D. Ball and can be checked there.
This behavior had changed.
Take a look at the
how-to guide.
Add:
spring.jpa.defer-datasource-initialization: true

Spring MVC annotation with XML performance

I had previously used Spring MVC and hibernate annotations in my Google web application project. It is taking some time to start the application after deployment.
For that reason, I am switching to a Spring MVC XML-based approach for the controller only. However, for service and DAO classes, #Service and #Repository annotations remain as is.
In my Spring XML I am doing as like below (there is no bean tag defined for service and DAO classes):
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />
<bean class="com.my.controller.UserController">
<property name="domainManager" ref="domainManager"/>
<property name="userProfileDao" ref="userProfileDao"/>
</bean>
Inside UserController, I am not using any #autowired annotation. I am using combination of annotations with XML. Are there any drawbacks of this approach? Am I going about this the wrong way?
The difference is not between using Annotation or XML, it's between Autowiring and "manually injecting beans".
EDIT: #Autowired and XML component scan are doing the same thing.
You can "manually inject" beans with both XML and full Java #Configuration, the equivalent of your example would be :
#Configuration
public class WebAppConfig {
#Bean
public UserDao userDao() {
return new UserDao();
}
#Bean
public UserController userController() {
UserController ctrl = new UserController();
ctrl.setUserDao(userDao());
return ctrl;
}
}
The question is quite accurate because the App Engine team itself has revealed that the App Engine runtime was bad at classpath scanning (which Autowiring does to find matches by Class).
The performance loss at instance startup time would occur if you were doing :
public class UserController {
#Autowired
private UserDao userDao;
// ...
}
See this video, especially the question from the Pivotal (Spring framework) contributor : http://www.youtube.com/watch?v=lFarE1hH0ss
Few people know about this issue. Using Spring AOP can even totally crash on the production runtime. See : Using Spring AOP on App Engine causes StackOverflowError
So about your use of XML, there is no "right or wrong". Personally I don't like writing XML since I feel like it's more error prone, but some people like to clearly separate their configuration from their code. I still use autowiring in production, since the startup time is not an issue for me. Do what you and your team feel comfortable with, just keep in in mind the GAE limitations.

Method WCF not recognizing a parameter Entity Framework

When a drupal application is consuming a WCF service that we inherited, it sends an xml that should result in an entity framework parameter. After some schema changes, we updated the entity framework model (edmx file). The problem is that when the client calls the service (with the same code as before) the usageritem parameter is not properly deserialized.
The call send to the method is the following:
<UpdateUsager xmlns="http://tempuri.org/">
<usageritem xmlns:a="http://schemas.datacontract.org/2004/07/CNVGestion.Domain" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Id="i1">
<EntityKey xmlns="http://schemas.datacontract.org/2004/07/System.Data.Objects.DataClasses" xmlns:b="http://schemas.datacontract.org/2004/07/System.Data" i:nil="true"/><a:ADR1>7 rue Diffonty</a:ADR1> ....
The method that receives this call has the following header:
public string UpdateUsager(fUsagerItem usageritem, bool checkonly){
The edmx where the entity is declared has the following header
<edmx:Edmx Version="2.0" xmlns:edmx="http://schemas.microsoft.com/ado/2008/10/edmx">
<!-- EF Runtime content -->
<edmx:Runtime>
<!-- SSDL content -->
<edmx:StorageModels>
<Schema Namespace="FRONT.Store" Alias="Self" Provider="System.Data.SqlClient" ProviderManifestToken="2005" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns="http://schemas.microsoft.com/ado/2009/02/edm/ssdl">
I wanted to know if there could not be a problem between the fact that this edmx was generated before using sql server 2005 and we are using sql server 2012 now to update it and we only changed the ProviderManifestToken="2005"..
Thank you for your help
Your question is a bit ambiguous - does the call to your service fails before entering your method or, if not, do you mean the parameter is null or some of its properties are null?
If the latter, I can only guess that updating the Entity Framework model from the database, changed the property order in fUsagerItem class. You can manually inspect the .xsd file referenced by service's WSDL and see how WCF expects the XML to be. Change the serialization order of properties with [DataMember(Order = ?)] attribute, though you'll have to put those in designer-generated classes (which is a bad idea).
It is generally considered that you shouldn't directly use entity framework objects in web service, especially when you consume the service from other frameworks like PHP. You have more control over the serialization process when you create your own Data Transport Objects: you can hide some properties or introduce new ones that don't exist in your database. If you can persuade your client to change their implementation, I'd recommend using DTO classes in your sevice (AutoMapper can help a lot mapping DTO objects to entities and vice-versa).

Guice and JSF 2

I'm trying to use Guice to inject properties of a JSF managed bean. This is all running on Google App Engine (which may or may not be important)
I've followed the instructions here:
http://code.google.com/docreader/#p=google-guice&s=google-guice&t=GoogleAppEngine
One problem is in the first step. I can't subclass the Servlet module and setup my servlet mappings there because Faces is handled by the javax.faces.webapp.FacesServlet which subclasses Servlet, not HttpServlet. So, I tried leaving my servlet configuration in the web.xml file and simply instantiating a new ServletModel() along with my business module when creating the injector in the context listener described in the second step.
Having done all that, along with the web.xml configuration, my managed bean isn't getting any properties injected. The method is as follows
#ManagedBean
#ViewScoped
public class ViewTables implements Serializable
{
private DataService<Table> service;
#Inject
public void setService( DataService<Table> service )
{
this.service = service;
}
public List<Table> getTables()
{
return service.getAll();
}
}
So, I'm wondering if there is a trick to get Guice injecting into a JSF managed bean? I obviously can't use the constructor injection because JSF needs a no-arg constructor to create the bean.
Check the following JSF-Guice integration framework/advice:
http://code.google.com/p/jsf-sugar/
http://notdennisbyrne.blogspot.com/2007/09/integrating-guice-and-jsf.html
http://cagataycivici.wordpress.com/2007/03/26/integrating_guice_and_jsf/
http://snippets.dzone.com/posts/show/7171
You can also create an HTTP servlet that then simple delegates the request on to a FacesServlet (like a wrapper). This should give you the same effect using Guice Servlet.
How about this approach, works well for us:
http://uudashr.blogspot.com/2008/12/guicing-jsf-with-guice.html
being the developer of jsf sugar I really would like to know the problem you had using it. We are already using it in production here so there shouldn't be any "show stoppers", maybe something is just not well documented? Just drop me a mail: murbanek(at)gmx_net (replace the _ with a .) .
check out http://code.google.com/p/guice2jsf/, and website starchu.blogspot.com, it has excellent library that provides Guice and JSF 2.0 integration
As information in this post are getting out of date but the question is still relevant, I'd like to share my findings about this topic. I wrote a little tutorial including a runnable sample project on how to setup a fully guice powered web stack. You can find it here: https://github.com/skuzzle/guice-jsf

Resources