Now objectContextMap is static, so only one context is allowed per domain name (for entire app). Map should be created on the fly if needed, in bind()
2009/9/14 Arnaud Garcia <[email protected]> > OK, so I just change by adding new ObjectContext to a Map and set/get > this Map from the ThreadLocal which is only as the map created one > time... > But, I still have the same error sometimes.... > > below the new code if you can have a quick look... > > many thanks, for help ! > > arnaud > > --------------------------------------------------------------------------------------- > public class ImagemedBaseContext { > > private static Map<String, ObjectContext> objectContextMap = > Collections.synchronizedMap(new HashMap<String, ObjectContext>()); > private static final Logger log = > Logger.getLogger(ImagemedBaseContext.class.getName()); > protected static final ThreadLocal<Map<String, ObjectContext>> > threadObjectContext = new ThreadLocal<Map<String, ObjectContext>>(); > > public static ObjectContext getThreadObjectContext(String domain) > throws IllegalStateException { > ObjectContext context = threadObjectContext.get().get(domain); > if (context == null) { > throw new IllegalStateException("Current thread has no > bound ObjectContext."); > } 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) { > objectContextMap.put(domain, context); > threadObjectContext.set(objectContextMap); > if (context == null) { > log.fine("[UNBIND OBJECT CONTEXT]"); > } else { > log.fine("[BIND OBJECT CONTEXT] ObjectContext (" + > context.hashCode() + ") for domain=" + domain + " to ThreadLocal (" + > threadObjectContext.hashCode() + ")"); > } > } > } > > --------------------------------------------------------------------------------------- > > --------------------------------------------------------------------------------------- > > 2009/9/11 Andrey Razumovsky <[email protected]>: > > 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 > > > -- Andrey
