Apr 17th, 2006, 01:47 AM
Data source per client.
I'm looking for best way to redirect web app client to his particular db.
Clients may change dynamically.
Note , I have some solution and you are welcome to propose some improvement.
My question is not simple how it seems to me.
I need authoritative approval regarding some tricky but interesting solution.
I’ll be happy to get any advice and/or criticism.
Let me describe our environment first:
1)Imagine web application (packaged in xxx.war to be pedant), using spring-hibernate pair as universal approach to track user session, provide transaction management, map objects to db schema and so on…Regular architecture, commonly used in tutorials if not in production development..
Axis jars packaged together with other dependencies jars in our xxx.war.
Clients of our web application send their requests as SOAP messages to our webservice,
which is registered in Axis.
Webservice in turn redirects these requests to business logic objects.
It is also common approach.
All business logic objects described as beans in appContext.xml.
We need to keep web session notation (that means bean created and works in http session scope), when create business logic beans, so we marked our beans in appContext.xm as aop:scope type=session.
This is true for data access and persistent business object beans (DAO, BPO).
So when new http session started, new DAO, BPO objects always created.
Now is our problem and tricky solutions we have got.
Our web application would serve to several clients: every client has his personal data base!
We need some approach to change data source depend on client’s credentials.
So every client’s request should be analyzed and depend on client’s data (data saved in session or sent in SOAP header for instance) corresponded data source should be provided.
So client A will connect to db A, client B to db B and so on….
We use org.springframework.orm.hibernate3.LocalSessionFac toryBean as session factory and its property “data source” points in turn on DriverManagerDataSource.
We separated business logic from spring configuration completely!
That means all business logic is kept in separate jar and deployed separately from web application. In turn web application is just WEB-INF folder with appContext.xml and web.xml inside. No classes except that.
How does it work?
We deploy our business logic in separated jar, actually we put this jar in some common bootstrap time loading place (/lib on jboss) and so it visible for every web application as well. Also we put there all our dependencies(axis, spring, hibernate and so on).
Then every client deploys his own web application with his own appContext.xml , his own webservice mapping url, his own data source.
It is very comfortable solution, deployment of new client is very easy. Just put it in hot deployment folder and wow! It works.
The single but frustrating drawback is deployment of business logic jar an all its dependencies. Just put it in lib folder is easy but exceptions prone, because some dependencies may conflict with proprietary web server staff, for example if axis or hibernate or logger or ANY OTHER already installed on this particular web server and putting my jars may cause conflict…
It is very desirable to load my business and dependencies jars in some way, that avoid potential conflicts with other classes.
Moving forward we deployed our business logic and xxx.war in EAR.
It will be probably solution for classloading problem described above, but causes other problem: deployment of new client(xxx.war) is not silent.
I describe it in details:
If I simply add new xx1.war to myApp.ear folder then my new web client will not “see” jars until I add additional web module in EAR’s deployment descriptor. This procedure causes automatic redeploy and restart of ALL business logic, so all clients will be stopped and started. It is serious drawback.
This is first point, if you have any idea you are welcome to make advice.
We left the idea of separate deployment of every client and trying to make effort in order assign separate appContext to every client using ws handler.
How does it work?
JAX RPC handler checks user credentials and assign separate appContext file to every user:
It is code from handler’s processing:
String clientName = ..//get name from message header.
ApplicationContext ctx = new FileSystemXmlApplicationContext("C:/temp/contexts/"+clientName+".xml");
As you see we use ThreadLocal to pass ctx to business logic.
On business logic side we retrieve appContext assigned to thread and use it.
So every client has his separate copy of his app context.
Strange (and here is my next question), but we still require EMPTY appContext.xml in WEB-INF folder to start. Otherwise deploy does not work.
Why I need this EMPTY appContext.xml? Who requires it?
What possible drawbacks of such solution, although it works fine, but what is possible side effects?
I checked session scope beans - they are created in every session , so AOP works even when I retrieve appContext from local file and not from WEB-INF, it is not clear for me why session notation is not broken as if it works in web context, but I still need empty context file in WEB-INF? How does it work?
How can I clearly debug spring processes?
I’m afraid I may damage some sensitive mechanisms by my logic, but I don’t know actually what may it be….
Thanks for your attention and I suppose you find it interesting to discuss.
Last edited by Peter Kovgan; Apr 17th, 2006 at 08:05 AM.
Apr 17th, 2006, 06:51 AM
Both solutions work, but new problem is obvious:
Business objects are not shared between different app contexts, so every client has his own instance of business service.
That means we have a lot service objects in memory. How to share them between different app contexts and still use Spring transaction manager?
<bean id="txManager" class="org.springframework.orm.hibernate3.Hibernat eTransactionManager">
<property name="sessionFactory" ref="dao.session.factory"/>
<bean id="customer.service" class="org.springframework.transaction.interceptor .TransactionProxyFactoryBean">
<property name="transactionManager" ref="txManager"/>
<property name="target" ref="customer.service.target"/>
Last edited by Peter Kovgan; Apr 17th, 2006 at 07:05 AM.