PDA

View Full Version : Problems using scoped-proxy


insane
Apr 23rd, 2007, 04:12 AM
Hi,
I have web application that uses some configuration file that should be loaded from some location when there is proper request for it. This request contains this url (it's an address to FTP server) and all necessary data like user, password etc. I have defined a map that contains some keys and previously loaded configurations (each of these keys was previously delivered in the request). And when there is a request for some configuration (so, there is one of these keys in the request) ConfigurationLoader should fetch proper configuration from the map.

I hope so far everything is clear :-).

So, how it's made:

We have an EntryController that searches the request for all data necessary to connect to FTP server to get configuration file from. If all data is found and this data is correct, downloaded configuration file is put in the map at the key passed also in request. Configuration of this part looks like this:
<bean id="entryController" class="com.iim.web.spring.controllers.EntryController">
<property name="configurations">
<ref bean="configurations" />
</property>
</bean>
where configurations is:
<bean id="configurations" class="java.util.HashMap" />

Ok. Another part is ConfigurationFactory that is responsible for fetching proper configuration from the map using the given key:
<bean id="configurationFactory" class="com.iim.imagemanager.ConfigurationFactory" />

and it's code:
public class ConfigurationFactory {

private Map<String, Configuration> configurations;

public Configuration fetchConfiguration() {
String id = ((WebRequest) RequestContextHolder.currentRequestAttributes()).g etParameter("id");
if (id != null && id.length() > 0) {
Configuration configuration = configurations.get(id);
if (configuration != null)
return configuration;
}

return null;
}
}

And at last, configuration:
<bean id="configuration" factory-bean="configurationFactory" factory-method="fetchConfiguration" scope="session">
<aop:scoped-proxy />
</bean>

So... As you can see, I'm trying to use scoped proxy to inject proper configuration to all beans that needs it. But I get a bunch of errors when I try to restart this application (I paste only a small part of them, if whole stack is needed I can paste it but it's quite long):

Caused by:
org.springframework.beans.factory.BeanCreationExce ption: Error creating bean with name 'scopedTarget.configuration': Scope 'session' is not active for the current thread; consider defining a scoped proxy for
this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web
request? If you are actually operating within a web request and still receive this message,your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListen
er or RequestContextFilter to expose the current request.
Caused by:
java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request? If you are actually operating within a web request and still receive
this message,your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.

Well, I set session scope, I used aop:scoped-proxy... I don't know what is still wrong. Any ideas?

Jörg Heinicke
Apr 23rd, 2007, 05:16 AM
Hmm, the error message should be quite clear, you need to use either RequestContextListener or RequestContextFilter.
That's independent from <aop:scoped-proxy /> but necessary for the request or session scope.

Jörg

insane
Apr 23rd, 2007, 07:02 AM
Well, yes I forgot to write that I have set RequestContextListener and I also tried RequestContextFilter instead. Both give me same error.
Here's how I tried to use listener (in web.xml file):
<listener>
<listener-class>org.springframework.web.context.request.RequestCon textListener</listener-class>
</listener>
and filter:
<filter>
<filter-class>org.springframework.web.filter.RequestContextFilte r</filter-class>
</filter>

Jörg Heinicke
Apr 23rd, 2007, 08:18 AM
Hmm, ok, that would have been the simple solution. Now I need to try to understand your setup ;)

3 strange things:


How is the map "configurations" related to "configuration"? "configurations" is injected into the controller. Is it also injected into the ConfigurationFactory?
ConfigurationFactory access RequestContextHolder.currentRequestAttributes() directly while the session scope uses this internally anyway. Is this by intention?
With the RequestContextListener applied you should NEVER get this exception. Are you doing anything with threads (breaking the ThreadLocal used in RequestContextHolder)?


Could you please post the important part of your stacktrace (first 10 lines or so)? It would be interesting to see which RequestContextHolder.currentRequestAttributes() fails - yours in ConfigurationFactory or Spring's interal one in the session scope.

Regards
Jörg

insane
Apr 23rd, 2007, 09:12 AM
1. How is the map "configurations" related to "configuration"? "configurations" is injected into the controller. Is it also injected into the ConfigurationFactory?

Configurations map stores all configuration files. So far it is only used in this one controller. Later I will inject this object into all other controllers that needs it. First thing I found after your post is that I forgot to inject configurations to ConfigurationFactory. But even after this operation I still get the same error.

2. ConfigurationFactory access
RequestContextHolder.currentRequestAttributes() directly while the session scope uses this internally anyway. Is this by intention?

I'm not sure if I did it correctly. I think, the best way is to explain some bigger part of this process.
This application operates on FTP. There is only one instance of this application and there can be many requests from different users that should have access to different FTPs. Each user in it's request should contain data necessary to download proper xml file with configuration to it's FTP (in this configuration there should be also more data that is not important here). Because different customers may use different web applications, as a key for each configuration file will be used user's application's session id. So when some user sends a request, he attaches his session id and if my application properly downloaded configuration file, this configuration is stored in "configurations" under session key. Next, user can connect to my application by sending it's session id and he gets access to proper FTP.
I hope now everything is clear :).

3. With the RequestContextListener applied you should NEVER get this exception. Are you doing anything with threads (breaking the ThreadLocal used in RequestContextHolder)?

I don't. Here's another part of my stack trace:
java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request? If you are actually operating within a web request and still receive
this message,your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.web.context.request.RequestCon textHolder.currentRequestAttributes(RequestContext Holder.java:102)
at org.springframework.web.context.request.SessionSco pe.get(SessionScope.java:80)
at org.springframework.beans.factory.support.Abstract BeanFactory.getBean(AbstractBeanFactory.java:279)
at org.springframework.beans.factory.support.Abstract BeanFactory.getBean(AbstractBeanFactory.java:156)
at org.springframework.aop.target.AbstractPrototypeBa sedTargetSource.newPrototypeInstance(AbstractProto typeBasedTargetSource.java:58)
at org.springframework.aop.target.PrototypeTargetSour ce.getTarget(PrototypeTargetSource.java:30)
at org.springframework.aop.framework.Cglib2AopProxy$D ynamicAdvisedInterceptor.getTarget(Cglib2AopProxy. java:640)
at org.springframework.aop.framework.Cglib2AopProxy$D ynamicAdvisedInterceptor.intercept(Cglib2AopProxy. java:595)
at com.iim.imagemanager.Configuration$$EnhancerByCGLI B$$babf45f5.getSeparator(<generated>)
at com.iim.web.ftp.FTPLocalizer.<init>(Unknown Source)
at sun.reflect.NativeConstructorAccessorImpl.newInsta nce0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInsta nce(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newI nstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Construc tor.java:494)
at org.springframework.beans.BeanUtils.instantiateCla ss(BeanUtils.java:84)
at org.springframework.beans.factory.support.SimpleIn stantiationStrategy.instantiate(SimpleInstantiatio nStrategy.java:78)
at org.springframework.beans.factory.support.Construc torResolver.autowireConstructor(ConstructorResolve r.java:156)
at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.autowireConstructor(Abs tractAutowireCapableBeanFactory.java:684)
at org.springframework.beans.factory.support.Abstract AutowireCapableBeanFactory.createBeanInstance(Abst ractAutowireCapableBeanFactory.java:622)

insane
Apr 24th, 2007, 04:34 AM
Ok, I found out what's wrong. First of all - no RequestContextFilter/Listener was necessary. I use DispatcherServlet and it does all. The problem was somewhere else (I still don't know why Spring was displaying different errors). There were some objects in application that needed "configuration" object (the one instantiating using scoped-proxy) in constructors and these objects where creating and injecting by Spring when application starts. So, there was a problem with these objects cause Spring was uneble to give them proper "configuration" object.

Jörg Heinicke
Apr 24th, 2007, 07:25 AM
Actually I had exactly this idea when seeing your stacktrace as getSeparator() is called on the Configuration object in the constructor of FTPLocalizer:


at com.iim.imagemanager.Configuration$$EnhancerByCGLI B$$babf45f5.getSeparator(<generated>)
at com.iim.web.ftp.FTPLocalizer.<init>(Unknown Source)

Unfortunately, I hadn't the time to answer to your post yesterday. Nice, you figured it out anyway :)

Jörg