This forum is now a read-only archive. All commenting, posting, registration services have been turned off. Those needing community support and/or wanting to ask questions should refer to the Tag/Forum map, and to http://spring.io/questions for a curated list of stackoverflow tags that Pivotal engineers, and the community, monitor.

AnnouncementAnnouncement Module

Collapse

No announcement yet.

Setting up the contextSource bean using info from Database instead of XML filePage Title Module

Those information are stored on a Database, and I would like to retrieve them and to use them... but I don't know how to map these information in order to set up the contextSource bean when the application is started (using the class StartupListener)!

I already have getter methods to retrieve the information I need; I just don't know how to set up the bean...

Comment

thanks for your reply. I tried to post a similar topic in the Core Container section yesterday but apparently it was not published...

I have to say I don't really understand the link you gave... I'm quite of a beginner at Java Beans and I didn't understand how to reach a value stored in a specific table on a specific database...

The thing is I already have a proper manager for this table (called PARAM), so I can reach any parameter with a getter. The only thing I don't understand is how to set the bean dynamically, in a way...

And yes, I know it's not a good idea for security purpose, but it's the easiest way when you have to deal with several developer, validation and production environment instances (cause of course, the properties on the development database is not the same as the ones on the production database)...

Comment

I would probably create a custom FactoryBean for creating and setting up the ContextSource. The FactoryBean would subclass AbstractFactoryBean be responsible for retrieving the required data from DB (or the manager you're referring to) and creating and setting the properties on a LdapContextSource. Please note that if you are creating your ContextSource manually you need to explicitly call afterPropertiesSet() after setting the configuration parameters.

Comment

I would probably create a custom FactoryBean for creating and setting up the ContextSource. The FactoryBean would subclass AbstractFactoryBean be responsible for retrieving the required data from DB (or the manager you're referring to) and creating and setting the properties on a LdapContextSource. Please note that if you are creating your ContextSource manually you need to explicitly call afterPropertiesSet() after setting the configuration parameters.

Thanks for these clues... but as I said, I'm a beginner, and althought I learned many things from your message, I still lack the very basic to understand what to do (sorry...).

My Web application is currently working with this piece of XML code to define the beans:

I looked at LdapContextSource source code, and it extends AbstractContextSource. What I don't understand is what is called with the above XML piece of code? There is no constructor in LdapContextSource, and no constructor in AbstractContextSource. So what exactly happens when my server is launched and falls on the XML code?

I suppose I shall replace the current contextSourcebean with something like

Where MyContextSourceFactory will be the piece of Java code that will use my ParamManager to retrieve the info from the DB.

Since this bean will be used by the ldapTemplate bean, and ldapTemplate is expecting a ContextSource as a parameter, how to implement such a bean in Java? I honestly have no idea, and I don't know where to look for examples... and the source code is definitely obscure to me

I tried to write MyContextSource.java, but since I have no idea what to do (I don't know how to return the ContextSource the LdapTemplate is waiting for since I don't know how a class called from a bean works), I did crap (I don't even dare showing you what I did !) and got this while running my application:

Comment

I would love to help you out in more detail, but I'm sitting a little tight at the moment. Please have a look at Chapter 3 of the Spring manual, and in particular the section on FactoryBean. Experiment with Spring without involving Spring LDAP, to get the concepts clear. Then get back here and we'll see what we can do.

Comment

I noted a small error when reading through it quickly. In section "Objects obtained from ’strange’ locations", Alef writes:

We can just ‘new’ a DataSource because we want to have the DataSource configured in JNDI.

What he most likely meant was that we can not just 'new' a DataSource. The paragraph should read:

Consider objects obtained from a JNDI context like DataSources. We can not just ‘new’ a DataSource because we want to have the DataSource configured in JNDI. So it has to be explicitly retrieved from the JNDI tree by creating a new InitialContext and using its lookup() method. Not exactly JavaBean-friendly. Because we still want to wire DataSources in our Spring context for example we need some level of indirection. The FactoryBean provides a solution.

For now, I'm just testing it with direct values, and it works fine, but obviously does nothing more than the previous XML definition.

So instead of

Code:

this.url = "ldaps://xxx:636";

I would like something like

Code:

this.url = paramManager.getUrl();

Where the paramManager is the Manager I'm using to get all the info I need from the DB.

The problem is this Manager is defined during the startup, and the only way to get it is to get the Application Context method getBean("paramManager"). But at the time MyContextSource is called, paramManager is not accessible... Well, maybe it is, but I don't know how to access it! Any idea?

There is probably something to do in the StartupListener (I'm using AppFuse, and StartupListener is a class defined to initialize the needed info at startup), but setting up in the StartupListeneer would be too late since ldapTemplate is initialized before the call to StartupListener... I don't know what to do and am stuck, again =_=

Comment

To summarize: the problem is that we want to set the ContextSource properties using values retrieved from a database rather than from a properties file. The context configuration file looks something like this:

I skipped the ContextSourceFactoryBean approach and went back to look at the post about using Apache Commons Configuration from my colleague Alin Dreghiciu. I got it working. At the moment, the database must be running before the context is loaded. We will assume it contains this information:

The DatabaseConfiguration performs all the work necessary to read properties from a database table. The internal configuration format is converted into standard Properties by the ConfigurationConverter:

Note that we're using normal bean dependencies and no custom Java code. Spring will make sure that the sequence is correct. It goes like this:

The PropertyPlaceholderConfigurer is a BeanFactoryPostProcessor, so before any beans are created, it will be called on to replace property placeholders from its set of properties. However, in order to be instantiated, it does need a few beans.

First of all, the configurer needs the myPropsFromFile bean, which will be created and load the db.properties (containing JDBC driver, url and such).

Having the myPropsFromFile bean allows the MethodInvokingFactoryBeans to get the database properties mentioned above.

This in turn allows the DataSource and the DatabaseConfiguration to be created.

The myPropsFromDb bean is created using a somewhat advanced version of the factory-method concept. The bean is actually the result of a call to the static method ConfigurationConverter.getProperties that takes the DatabaseConfiguration bean as argument and returns a Properties object containing all the properties from the database. Confusing? Read more here and here.

The PropertyPlaceholderConfigurer does now have all its required beans. It will go through the context and replace all ${} placeholders with the corresponding property value.

The problem is this Manager is defined during the startup, and the only way to get it is to get the Application Context method getBean("paramManager"). But at the time MyContextSource is called, paramManager is not accessible... Well, maybe it is, but I don't know how to access it! Any idea?

If you inject "paramManager" to the FactoryBean using a setter (or a constructor argument) you should be OK I think. Also, you should not implement FactoryBean directly, but subclass from AbstractFactoryBean and implement createInstance instead.

When loadProperties is called, ParamManager connects to the database and fills a Map with the keys and values from the given configuration table. Note the generic getProperty method.

Time for the ContextSourceFactoryBean. As Mattias noted, it's good practice to extend from AbstractFactoryBean. We give it a ParamManager property, which we later will configure Spring to inject for us.

Et voilà... since paramManager can get all the info I need, the job is done.

1. the bean myContextSource is initialized using the existing paramManager bean as its constructor argument, allowing it to get the info needed from the DataBase;
2. createInstance is called in order to return the LdapContextSource the ldapTemplate Bean is asking for.

Once again, thank you very much; I really learnt many things those past days thanks to you!