Database access from session bean

Hello,

I have a stateless session bean which performs some complex

calculations, and also does some database access.

For the database access the bean class has a datasource as

follows:

public class TestBean implements SessionBean {

private DataSource ds_;

public void ejbCreate() {

getDataSources();

...

}

private void getDataSources() {

try {

Context ictx = new InitialContext();

ds_ = (DataSource)ictx.lookup("java:comp/env/jdbc/TestDB");

} catch (Exception e) {

e.printStackTrace();

throw new EJBException(e);

}

}

...

}

Now this class has a method (which is also in the remote interface)

calculateSomething(). This method constructs a number of other

objects that do the actual calculation, and one of these objects

does the actual database access. How would another object be able to

use the datasource that was constructed in the bean class?

I could pass the datasource reference to that object, but that would

break my encapsulation. This is because that object does not get

created directly by the bean object, but rather the way the objects

interact is something like A -> B -> C, where A is the TestBean, and

C is the object that does the DB access. If I passed the datasource,

I would need to make B aware of the datasource, which doesn't

seem good design, because B doesn't do any database access.

Alternatively I could do the lookup in class C, but that would

degrade the performance, as an object C gets created and destroyed

every time the calculateSomething() method is called.

A third option I have thought of, is to add a public method to the

bean that returns a connection. Whenever another object gets

created, a reference to the bean object will be passed along. Then,

if another object needs to do database access, it will call back

the bean to get a connection. This seems just as bad (if not worse)

than the first option.

Does anyone have an elegant solution for this situation? What is

the best practice of handling datasources when a bean class doesn't

do the database access itself? In all the examples I've seen so far,

all the functionality was in the session bean class, but again that

doesn't seem good OO design, and would result in a single huge class.

regards,

Kostas

[2526 byte] By [kostasa] at [2007-9-26 4:36:32]
# 1

I'm thinking aloud here, but you could make a MessageBean of your object "C" that just handles a request from either Bean "A" or object "B". You should encapsulate your data access with entity beans, and you're all in the EJB framework. Creating your own DB connection for this sort of "normal" uses is overkill. Let it to the container!

I hope that helps!

maasg at 2007-6-29 17:54:37 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 2

Thanks for your reply.

Sorry if I didn't make it clear in my original message but object A (the session bean) does not know - and should not know in order to have proper encapsulation - about C (the object that accesses the database). A creates B, and calls some method on it. Then B creates C which does the db access. Also B and C are normal objects, not EJBs.

Finally I am using EJB 1.1 so message beans are not available.

kostasa at 2007-6-29 17:54:37 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 3

Create a new Entity Bean that wraps the DB (either CMP or BMP, CMP is prefered). So in TestBean, you don't need datasource at all. Let C call the new Entity Bean for DB access. C will call the finder methods of the Entity Bean to get the data it needs. Performance is not a problem since C has to do a DB query in any case. The datasource lookup part is handled by the Entity Bean, which does NOT come and go like C does (as you worried). With CMP, it's even better, the server handles everything and your C only does query (i.e. finder methods). One advantage is if 2 C objects happen to use the same data, then the Entity Bean representing that "same data" is already loaded in the server after first use, the 2nd C object can reuse it without getting it from DB again.

Actually this is the elegant way that EJB is supposed to be used.

yilin at 2007-6-29 17:54:37 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 4

You may like to think about a Factory that returns the Db connection from a pool, in such a way that object C gets just a reference to that connection and perform its calculations.

Nevertheless, I've to comment about your approach: You're worried about a 'good' OO approach, but letting an object do calculations *AND* access the database.

Shouldn't you do the following:

Bean A access DB and gathers needed data.

Bean A calls "B" with the data (possibly a data structure) and gives that to "C" so it can perform its calculations. After that "C" returns the results up to "A" and "A" writes what is needed to the database.

I don't see the need for "B", but I'm sure you have some task for it in the actual implementation.

"Divide and Conquer"

BTW: what is the name of your "C" object? CalculateComplexDataFromDBandUpdate? See my point?

I hope that helps.

Greetings.

-G.

maasg at 2007-6-29 17:54:37 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 5
Have a look at this article of Javaworld. It can be of some help for you... http://www.javaworld.com/javaworld/jw-09-2000/jw-0929-ejbframe.html
maasg at 2007-6-29 17:54:37 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 6

Thanks again to both for the replies. Here are my responses:

Yi Lin: Yes, I know that an entity bean would solve this problem, however it has been decided not to use entity beans so this is not my call (I think the reason entity beans are not allowed in this project is that they are considered risky: there are other applications that access the same database, so if the container caches entity bean data as you describe, then the users might get inconsistent results).

Gerard: Actually object B is the one that has the business logic and C is a peer object that only does database access and no calculaitons. For example B can be Customer, and C CustomerDB. This is why object B does not have any knowledge of datasources or connections. So my design does not appear to be that bad!

As far as the factory you propose is concerned, I cannot understand how this would solve my problem. In order to solve this situation the factory would need to be persistent, i.e. get created by the ejbCreate() method, and destroyed whenever the container decides to destroy the bean. There would be no point in object C creating the factory, as I would have the overhead of doing the JNDI lookup every time I create a C.

So the question remains the same: how would I pass a reference to the factory from A to C without making B aware of it?

kostasa at 2007-6-29 17:54:37 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 7
If that's the reason not using Entity Bean, then use BMP entity bean. Since you write JDBC code directly in the Entity Bean (the same JDBC code in your C right now, right?), there is not out-of-data problem.
yilin at 2007-6-29 17:54:37 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 8

Which server are you using? Specific servers have config option for you to force ejbLoad() each time an Entity Bean is called. This is exactly for your case where other app is also writing to the same db.

You can also do it yourself - you can call ejbLoad()/ejbStore() explicitly at the right spots of your Entity Bean.

yilin at 2007-6-29 17:54:37 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 9

Yi Lin: Yes I guess that it would be possible to have an entity bean that will not corrupt my data. Unfortunately it is not my call, and I am simply not allowed to use entity beans.

Currently I am tempted to create a connection factory implemented as a singleton, that gets initialized by the session bean class. Then the data access object C, would be able to access the initialized factory simply by knowing the class name. I think this is what Gerard may have meant.

Thanks both for your replies. I'll have another look tomorrow in case there are additional answers (and distribute the dollars too).

cheers,

Kostas

kostasa at 2007-6-29 17:54:37 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 10

You can use Singleton and Singleton can initialize itself when first called (no need to initialize from session bean). Be careful with multithreading on the singleton.

If your architect does not let you use Entity Bean, your EJB project has a problem - having an architect who does not really understand EJB. But many projects have such problem, as far as I know.

yilin at 2007-6-29 17:54:37 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...