Re: getThreadObjectContext with domain parameter - code -

From: Andrey Razumovsky (razumovsky.andre..mail.com)
Date: Mon Sep 14 2009 - 11:14:33 EDT

  • Next message: Arnaud Garcia: "Re: getThreadObjectContext with domain parameter - code -"

    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 <arnau..magemed-87.com>

    > 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 <razumovsky.andre..mail.com>:
    > > 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 <arnau..magemed-87.com>
    > >
    > >> 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
    



    This archive was generated by hypermail 2.0.0 : Mon Sep 14 2009 - 11:15:31 EDT