Well, looking at your code, I think you should not create new ThreadLocal each time request is received (in bindThreadObjectContext). You old bindings just get erased
2009/9/11 Arnaud Garcia <[email protected]> > Hello, > > I created a filter to use multi domains in a webapp, but I still have > a problem...., I don't find the bug... if someone can help me to fix > it ! > (I think that some people will also need this kind of filter, so this > is why I post the complete code) > > So, the last bug is that sometimes the ObjectContext cannot be > retrieved..... > java.lang.IllegalStateException: Current thread has no bound ObjectContext. > at > com.imagemed.cayenne.ImagemedBaseContext.getThreadObjectContext(ImagemedBaseContext.java:39) > > thanks > > Arnaud > > > To use the filter: > ---------------------- > > =>Declare the filter in web.xml as usual : > > <filter> > <filter-name>Imagemed.Cayenne</filter-name> > > > <filter-class>com.imagemed.cayenne.WebApplicationMultiDomainsContextFilter</filter-class> > </filter> > > <filter-mapping> > <filter-name>Imagemed.Cayenne</filter-name> > <url-pattern>/*</url-pattern> > </filter-mapping> > > Then in your DAO you retrieve your contexts from your session like this: > > ctxtForDomain1 = (DataContext) > ImagemedBaseContext.getThreadObjectContext("DOMAIN1"); > ctxtForDomain2 = (DataContext) > ImagemedBaseContext.getThreadObjectContext("DOMAIN2"); > .... > > Below you will find the complete code..... > > > ------------------------------ THE FILTER ------------------------- > package com.imagemed.cayenne; > > import java.io.IOException; > import java.util.ArrayList; > import java.util.Collection; > import java.util.logging.Logger; > import javax.servlet.Filter; > import javax.servlet.FilterChain; > import javax.servlet.FilterConfig; > import javax.servlet.ServletException; > import javax.servlet.ServletRequest; > import javax.servlet.ServletResponse; > import javax.servlet.http.HttpServletRequest; > import javax.servlet.http.HttpSession; > import org.apache.cayenne.access.DataContext; > import org.apache.cayenne.access.DataDomain; > import org.apache.cayenne.conf.Configuration; > import org.apache.cayenne.conf.ServletUtil; > > > public class WebApplicationMultiDomainsContextFilter implements Filter { > > public static final String DATA_CONTEXT_KEY = "cayenne.datacontext"; > private ArrayList<String> domains = new ArrayList<String>(); > private static final Logger log = > Logger.getLogger(WebApplicationMultiDomainsContextFilter.class.getName()); > > public static DataContext getSessionContext(HttpSession session, > String domain) { > synchronized (session) { > String dataCtxKey = DATA_CONTEXT_KEY + "." + domain; > DataContext ctxt = (DataContext) > session.getAttribute(dataCtxKey); > > if (ctxt == null) { > ctxt = DataContext.createDataContext(domain); > session.setAttribute(dataCtxKey, ctxt); > } else { > log.fine("[RETRIEVE] DataContext (" + ctxt.hashCode() > + ") retrieved from session key=" + dataCtxKey); > } > > return ctxt; > } > } > > public void destroy() { > } > > public void doFilter(ServletRequest request, ServletResponse > response, FilterChain chain) throws IOException, ServletException { > boolean reset = false; > > if (request instanceof HttpServletRequest) { > reset = true; > > HttpSession session = ((HttpServletRequest) > request).getSession(true); > for (String domain : domains) { > DataContext context = getSessionContext(session, domain); > ImagemedBaseContext.bindThreadObjectContext(context, > domain); > } > } > > try { > chain.doFilter(request, response); > } finally { > if (reset) { > for (String domain : domains) { > ImagemedBaseContext.bindThreadObjectContext(null, > domain); > } > } > } > } > > public void init(FilterConfig filterConfig) throws ServletException { > > ServletUtil.initializeSharedConfiguration(filterConfig.getServletContext()); > Collection<DataDomain> collDomains = > Configuration.getSharedConfiguration().getDomains(); > for (DataDomain dataDomain : collDomains) { > domains.add(dataDomain.getName()); > log.info("[FOUND DOMAIN] name=" + dataDomain.getName()); > } > } > } > > ------------------------------ ImagemedBaseContext ------------------------ > package com.imagemed.cayenne; > > import java.util.Collections; > import java.util.HashMap; > import java.util.Map; > import java.util.logging.Logger; > import org.apache.cayenne.ObjectContext; > > public class ImagemedBaseContext { > > private static Map<String, ThreadLocal> threadLocalMap = > Collections.synchronizedMap(new HashMap<String, ThreadLocal>()); > private static final Logger log = > Logger.getLogger(ImagemedBaseContext.class.getName()); > > public static ObjectContext getThreadObjectContext(String domain) > throws IllegalStateException { > ThreadLocal<ObjectContext> threadObjectContext = > threadLocalMap.get(domain); > ObjectContext context = threadObjectContext.get(); > > if (context == null) { > throw new IllegalStateException("Current thread has no > bound ObjectContext."); <============================ ligne 39 > } else { > log.fine("[GET OBJECT CONTEXT] ObjectContext (" + > context.hashCode() + ") for domain=" + domain + " to ThreadLocal (" + > threadObjectContext.hashCode() + ")"); > } > return context; > > } > > public static void bindThreadObjectContext(ObjectContext context, > String domain) { > ThreadLocal<ObjectContext> threadObjectContext = new > ThreadLocal<ObjectContext>(); > threadObjectContext.set(context); > threadLocalMap.put(domain, threadObjectContext); > if (context == null) { > log.fine("[UNBIND OBJECT CONTEXT]"); > } else { > log.fine("[BIND OBJECT CONTEXT] ObjectContext (" + > context.hashCode() + ") for domain=" + domain + " to ThreadLocal (" + > threadObjectContext.hashCode() + ")"); > } > } > } > -- Andrey
