Configurable number of Spring DAO objects - spring

I have an app that access a configurable list of databases. I do not want to hardcode the corresponding DAO objects in the class. Is there a way to do that in Spring?
The hardcoded way would be:
databases.properties:
db1.url = jdbc://db1.acess.com:3306
...
db2.url = jdbc://db2.access.com:3306
...
db3.url = ldap://ldapdb.access.com:3306
applicationContext.xml:
<bean id="MyServicebean" class="com.MyServiceImpl">
<property name="DBDao1" ref="DBDao1"/>
<property name="DBDao2" ref="DBDao2"/>
<property name="LdapDao" ref="LdapDao"/>
</bean>
public class MyServiceImpl {
#Autowired
private DBDao DBDao1;
#Autowired
private DBDao DBDao2;
#Autowired
private LdapDao LdapDao;
...
}
Is there a more flexible way of configuring and autowiring DAO objects based on how many DBs we specify in databases.properties?

Looking at your database.properties, it seems not all DAOs are connecting to Databases. Some are connecting to LDAP server. So obviously implementation of DAOs will be different and can't generalize/abstract it.
If all DAOs that connect to databases perform the same set of operations and connects to different databases based on some criteria (ex: clientId) then take a look at Spring's AbstractRoutingDataSource. http://spring.io/blog/2007/01/23/dynamic-datasource-routing/

Related

Get a message converter bean in Spring boot

I am trying to instantiate a resolver from spring-cloud-aws-messaging, specifically the NotificationMessageArgumentResolver. The problem is that it takes a MessageConvertor as an argument. So, this is what I have so far:
private NotificationMessageArgumentResolver notificationMessageArgumentResolver() {
new NotificationMessageArgumentResolver(this.messageConvertor);
}
To get the messageConvertor, I have tried:
#Autowired
public MvcConfig(MessageConvertor messageConvertor) {}
#Autowired
public MvcConfig(MappingJackson2MessageConverter messageConvertor) {}
but I get the same error either ways no bean found. The documentation is simply asking to use the XML:
<mvc:annotation-driven>
<mvc:argument-resolvers>
<ref bean="notificationResolver" />
</mvc:argument-resolvers>
<aws-messaging:notification-argument-resolver id="notificationResolver" />
Which, according to the doc
registers three argument resolvers: NotificationStatusHandlerMethodArgumentResolver, NotificationMessageHandlerMethodArgumentResolver, and NotificationSubjectHandlerMethodArgumentResolver.
So, following the answer from How to use argument-resolvers using annotation in Spring boot?, I am able to get 2 of the 3 beans added, as they don't need any beans I cannot access, however I am not able to instantiate NotificationMessageArgumentResolver due to the lack of a MessageConvertor. I am expecting all my messages to come purely in JSON, so I do know exactly which MessageConvertor to use, which is the default one for JSON that ships with Spring Boot.
EDIT
The entire file, if anyone is interested: http://pastebin.com/tM471AEv
I wonder if you really need the NotificationMessageArgumentResolver as that is intended to be used when using messaging. As you can see it implements the HandlerMethodArgumentResolver from the org.springframework.messaging package.
I suspect that you want to use the NotificationMessageHandlerMethodArgumentResolver instead. Which is the HandlerMethodArgumentResolver for use with the web instead of messaging. Which is also registered when using <aws-messaging:notification-argument-resolver id="notificationResolver" />
I would also suggest to use the NotificationHandlerMethodArgumentResolverFactoryBean instead of 3 individual beans as that is also the class that is used internally by the namespace and annotation driven configuration.
Your configuration would look something like this.
#Bean
public NotificationHandlerMethodArgumentResolverFactoryBean notificationHandlerMethodArgumentResolverFactoryBean() {
return new NotificationHandlerMethodArgumentResolverFactoryBean();
}
#Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(notificationHandlerMethodArgumentResolverFactoryBean.getObject());
}

Spring Hibernate - Set static final String to indicate the schema of Hibernate entity

I have domain objects mapped as Hibernate entities stored in 2 distinct schemas of an Oracle database. Unfortunately, one of this schema has not the same name between Test and Prod environment database.
To avoid changing manually the schema in the code each time I deploy on such or such environment, my idea was to use a Spring property placeholder to get values in a properties file depending of the environment. Then using MethodInvokingFactoryBean to set those properties in useful static Utility class.
Spring's conf setting values of static variables depending of properties read in a properties file with Spring's PropertyPlaceholderConfigurer :
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="com.company.app.Schemas" />
<property name="targetMethod" value="setSchemaNames" />
<property name="arguments">
<props>
<prop key="schema1">${schema1_name}</prop>
<prop key="schema2">${schema2_name}</prop>
</props>
</property>
</bean>
Then class hosting static schemas names :
public class Schemas {
public static String SCHEMA1;
public static String SCHEMA2;
public static void setSchemaNames(Map<String, String> schemaNames) {
Schemas.SCHEMA1 = schemaNames.get("schema1");
Schemas.SCHEMA2 = schemaNames.get("schema2");
}
}
Fianlly Hibenate mapping :
#Entity
#Table(schema = Schemas.SCHEMA1, name = "item")
public class Item {
...
}
However to set the schema attribute of the #Table Hibernate annotation, I cannot use "static" variables, I must use "final static" variables (constant). So the last piece of code above does not compile.
I did not succeed to set "final static" variable with Spring's MethodInvokingFactoryBean. How could I do ?
In theory you could create a class which accesses the public static final fields and us reflection to make them accessible and set the value.
Field field = ReflectionUtils.findField(Schemas.class, "SCHEMA1");
field.setAccessible(true);
ReflectionUtils.setField(field, target, "MySchema");
However even with that in place it will never work. The constants in the Item class will be inlined, at compile time, with the actual value. If you would decompile your Item class it would look something like the following.
#Entity
#Table(schema = null, name = "item")
public class Item {
...
}
That is simply the way constants work in java (or better the java compiler).
I have domain objects mapped as Hibernate entities stored in 2 distinct schemas of an Oracle database. Unfortunately, one of this schema has not the same name between Test and Prod environment database
This might help you in your solution. Basically in your entities which have the constant schema in test en prod define the schema. For the other entities (different schema in test en prod) don't define a schema but simply set the hibernate.default_schema property in your configuration.

How to use low-level driver APIs with Spring Data MongoDB

I am using Spring Data MongoDB. But I don't want to map my result to a domain class. Also, I want to access low level MongoAB APIs in few cases. But I want spring to manage the connections pooling etc.
How can i get an instance of com.mongodb.MongoClient to perform low level operations.
Here is what I am trying to do :
MongoClient mongoClient = new MongoClient();
DB local = mongoClient.getDB("local");
DBCollection oplog = local.getCollection("oplog.$main");
DBCursor lastCursor = oplog.find().sort(new BasicDBObject("$natural", -1)).limit(1);
Or I simply want a JSON object / DBCursor / DBObject.
you can do it this way
#Autowired MongoDbFactory factory;
DB local = factory.getDB("local");
DBCollection oplog = local.getCollection("oplog.$main");
DBCursor lastCursor = oplog.find().sort(new BasicDBObject("$natural", -1)).limit(1);
Where
MongoDbFactory is an interface provifed by spring-data-mongo that can obtain a
com.mongodb.DB object and access allthe functionality of a specific MongoDB database
instance
your configuration file should contain these informations :
<bean id="mongoFactoryBean"
class="org.springframework.data.mongodb.core.MongoFactoryBean">
<property name="host" value="127.0.0.1"/>
<property name="port" value="27017"/>
</bean>
<bean id="mongoDbFactory"
class="org.springframework.data.mongodb.core.SimpleMongoDbFactory">
<constructor-arg name="mongo" ref="mongoFactoryBean"/>
<constructor-arg name="databaseName" value="local"/>
</bean>
doing it like that, spring should stay managing your connection pool.
You usually perform low level access through MongoTemplate's execute(…) methods that take callbacks giving you access to the native Mongo driver API.
class MyClient {
private final MongoOperations operations;
#Autowired
public MyClient(MongoOperations mongoOperations) {
this.operations = operations;
}
void yourMethod() {
operations.execute(new CollectionCallback<YourDomainClass>() {
YourDomainClass doInCollection(DBCollection collection) {
// here goes your low-level code
}
});
}
The advantage of this template approach is that the MongoTemplate instance backing the MongoOperations interface will still take care of all resource management and exception translation (converting all Mongo specific exceptions into Spring's DataAccessException hierarchy).
However, for your concrete example you could just go ahead and do the following directly:
Query query = new Query().with(new Sort(DESC, "$natural")).limit(1);
DBObject result = operations.find(query, DBObject.class, "oplog.$main");
Here you can mix and match the type you pass into the find(…) method to let the template convert the result into a Map or a domain object if needed. As indicated above you also get resource management and exception translation which your sample code above is missing.

Using session attributes in spring MVC

I am developing a web application using spring MVC. I just want a simple example of how to do session management in this. I have seen lot of forums but I am not able to get a clear picture of this
My requirement is
I have an object, which I would like to be accessible in all controllers and JSP's I
would like to set that in the controller and get that in JSP
I am looking for something like
Session.setAtribute();
Could you please let me know a very simple instance . Thank you
There are different ways of accessing servlet session in Spring MVC. But I think this one is the one that best suits your problem. You can create a session scoped bean, which holds your desired info:
#Component("myObjectHolder")
#Scope(WebApplicationContext.SCOPE_SESSION)
public class MyObjectHolderImpl implements MyObjectHolder {
private long userId;
private String username;
private Theme theme;
// Getters & Setter
}
Then, you can access to it from other beans:
#Controller
public class MyController {
#Autowired private MyObjectHolder myObjectHolder;
#RequestMapping
public ModelAndView switchTheme(String themeId) {
...
Theme newTheme = themeService.get(themeId);
myObjectHolder.setTheme(newTheme);
...
}
}
You can access directly from your view too, but you must configure it:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
...
<property name="exposedContextBeanNames" value="myObjectHolder" />
</bean>
And in your JSP:
Hi ${myObjectHolder.username}, you switched
application theme to ${myObjectHolder.theme.name}
The simplest approach is to access HttpSession directly by injecting it into your handler method:
#RequestMapping("/page")
public ModelAndView page(HttpSession session) {
session.getAttribute("foo");
}

Reading a "properties" file

I have a Rest service using Resteasy (running on top of Appengine), with the following psuedo code:
#Path("/service")
public class MyService {
#GET
#Path("/start")
public Response startService() {
// Need to read properties file here.
// like: servletContext.getResourceAsStream("/WEB-INF/config.properties")
}
}
However its obvious that the servlet context cannot be accessed here.
And code like:
InputStream inputStream = this.getClass().getClassLoader()
.getResourceAsStream("/WEB-INF/config.properties");
Can't be executed within the Appengine environment.
EDIT:
I have tried doing it with Spring like:
appContext.xml
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="/WEB-INF/auth.properties"/>
</bean>
Then, put this on the actual class fields:
#Path("/service")
public MyService{
#Autowired
#Value("${myservice.userid}")
private String username;
#Autowired
#Value("${myservice.passwd}")
private String password;
// Code omitted
}
However, part of the code of the MyService complains because the username and password was not "injected", I mean its empty although its on the auth.properties file
In RESTEasy you can easily inject Servlet context via #Context annotation: http://docs.jboss.org/resteasy/docs/2.3.1.GA/userguide/html_single/index.html#_Context
Examples can be found here: Rest easy and init params - how to access?
This should work if you put the file in /WEB-INF/classes/ (which, importantly, is on the classpath), specifying config.properties as a file at the top-level.
this.getClass().getClassLoader().getResourceAsStream("/config.properties");
See this similar question: How to load properties file in Google App Engine?
Edit: Now you've edited, I'll respond & answer the Spring-related question. So, put the auth.properties into /WEB-INF/classes/ , and then specify classpath as follows.
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:auth.properties"/>
</bean>

Resources