tags:

views:

361

answers:

3

I read this post, but I don't understand how I can gain access to the request using a ThreadLocal or DataSourceLookup or AbstractRoutingDataSource. I read every post but it still doesn't work.

How do I gain access to my request's dataSource parameters and dynamically create connections with them?

A: 

I'm not sure what parameters you mean, or what the request is. Are you trying to write a web app? Is this an HttpRequest? Are you determining what kind of data source you need based on the request?

Depending on the answers to those questions, you might not need to get dynamic access to the data source.

If you have multiple data sources, each serving a different kind of request, I'd suggest that the data sources should be injected into service objects, which are injected into web controllers, which are selected for a particular URL. You'll be able to vary the data source that way, and there's nothing funkier going on than URL mapping in the web tier.

Without knowing more about your use case, I'd guess that you're over complicating things because you're new to Spring and don't know how to use it properly yet. No insult intended, just a guess.

UPDATE:

"I can't change it" - you should at least discuss it with the client before assuming. This is a bad idea. Encrypting parameters won't save you.

You're better off creating a factory that a Controller can use to instantiate a factory that's injected with all the data sources you need. Store the data sources in a map and simply pass a key back and forth to get the data source. The Controller already has access to the Request; you shield users from having to know all those details about the database; you make the lookup a simple key (which I still don't like).

If it seems too hard, you probably shouldn't do it. There are easier ways. Rethink it.

duffymo
hi, i want to create multiple datasource beans with spring, but the connection parameters(url, driver, user, ...) are passed by another web application to my application, i`m using hibernate and i dont know how to pass the parameters in the request to create connections dynamicaly, i think the solution is at the end of this post:http://stackoverflow.com/questions/517353/how-to-design-daos-when-the-datasource-varies-dynamically/958563#958563but i dont understand how to gain access to the request using a ThreadLocal or DataSourceLookup or AbstractRoutingDataSource,thanks for the help...
Sorry, sounds like a design I wouldn't like much. Another web app passing connection parameters? Nope, this is the poorest kind of encapsulation there is. You're forcing a client to know all about the data sources you need? Wrong, wrong, wrong. Re-think it. That might be your first idea, but don't make it your last.
duffymo
Passing in those parameters means you don't get to take advantage of connection pooling, either. How can this scale?
duffymo
yep, i know but i cant change it, at least the parameters are encerypted... do you know how i cant access to the request using a threatlocal from a DataSourceLookup implementation???sorry for the grammar im latinoamerican...
+1  A: 

I think this is something like what the answer you linked to was getting at:

Warning: None of this has been compiled. None of this has been tested.

The CurrentRequestFilter is run once per request. It is responsible for storing the current request in a ThreadLocal that will be used later on.

public class CurrentRequestFilter extends OncePerRequestFilter {

    private ThreadLocal<HttpServletRequest> currentRequest;

    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) {
        currentRequest.set(request);
        filterChain.doFilter(request, response);
    }

    public ThreadLocal<HttpServletRequest> getCurrentRequest() {
        return currentRequest;
    }

    public void setCurrentRequest(ThreadLocal<HttpServletRequest> currentRequest) {
        this.currentRequest = currentRequest;
    }

}

The CurrentRequestDataSource has access to the same ThreadLocal as the CurrentRequestFilter.

public class CurrentRequestDataSource extends AbstractRoutingDataSource {

    private ThreadLocal<HttpServletRequest> currentRequest;

    @Override
    protected DataSource determineTargetDataSource() {
        HttpServletRequest request = currentRequest.get();

        String url = ...;
        String username = ...;
        String password = ...;
        DataSource dataSource = ...;

        return dataSource;
    }

    @Override
    protected Object determineCurrentLookupKey() {
        return null;
    }

    public ThreadLocal<HttpServletRequest> getCurrentRequest() {
        return currentRequest;
    }

    public void setCurrentRequest(ThreadLocal<HttpServletRequest> currentRequest) {
        this.currentRequest = currentRequest;
    }
}

You would then configure your bean definitions something like this:

<bean id="currentRequest" class="java.lang.ThreadLocal"/>

<bean id="currentRequestFilter" class="CurrentRequestFilter">
    <property name="currentRequest" ref="currentRequest"/>
</bean>

<bean id="dataSource" class="CurrentRequestDataSource">
    <property name="currentRequest" ref="currentRequest"/>
</bean>

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
</bean>

You must then make sure that the CurrentRequestFilter is registered in your web.xml file:

<filter>
    <filter-name>Current Request Filter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <init-param>
        <param-name>targetBeanName</param-name>
        <param-value>currentRequestFilter</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>Current Request Filter</filter-name>
    <servlet-name>Name_Of_Your_Servlet</servlet-name>
</filter-mapping>

Again, none of this has been tested, but hopefully it can offer some guidance.

Adam Paynter
All smells a bit funky to me - changing data sources according to request parameters (which have come from the users box remember) - but this looks like it should do the trick.
Nick Holt
For the record, I agree that is seems a bit funky. I wouldn't ever do it myself. I just just curious to see what the other fellow was recommending. Truth be told, the other fellow's answer wasn't dealing with creating new data sources from scratch. Rather, his was selecting between a few, pre-constructed data sources.
Adam Paynter
A: 

thanks for the advice, i`m designing a new architechture, thanks again for the comments