Re: getThreadObjectContext with domain parameter - code -

From: Arnaud Garcia (arnau..magemed-87.com)
Date: Tue Sep 15 2009 - 11:18:56 EDT

  • Next message: Robert Zeigler: "Re: Using Cayenne Servlet Filter can bring the web application down"

    ;-)
    many thanks it works well now.

    Arnaud

    2009/9/14 Andrey Razumovsky <razumovsky.andre..mail.com>:
    > Now you're creating new HashMap every request, and, as in your first
    > example, old bindings get erased. Bind method should be rewritten as
    >
    > public static void bindThreadObjectContext(ObjectContext context,
    > String domain) {
    >        Map<String, ObjectContext> objectContextMap =
    > threadObjectContext.get();
    >       if (objectContextMap == null) {
    >            objectContextMap = Collections.synchronizedMap(new
    > HashMap<String, ObjectContext>());
    >            threadObjectContext.set( objectContextMap);
    >
    >       }
    >        objectContextMap.put(domain, context);
    >
    > Or maybe there is something I don't understand :)
    >
    > 2009/9/14 Arnaud Garcia <arnau..magemed-87.com>
    >
    >> Well, I think there is something I don't understand, I change again
    >> and, no change..
    >> now I build a new hash, that I put on the ThreadLocal
    >>
    >> I am sorry but I don't understand why...
    >> Arnaud
    >>
    >> code below
    >>
    >>
    >> public class ImagemedBaseContext {
    >>
    >>    protected static final ThreadLocal<Map<String, ObjectContext>>
    >> threadObjectContext = new ThreadLocal<Map<String, ObjectContext>>();
    >>
    >>    public static ObjectContext getThreadObjectContext(String domain)
    >> throws IllegalStateException {
    >> .......
    >>  public static void bindThreadObjectContext(ObjectContext context,
    >> String domain) {
    >>         Map<String, ObjectContext> objectContextMap =
    >> Collections.synchronizedMap(new HashMap<String, ObjectContext>());
    >>         objectContextMap.put(domain, context);
    >>        threadObjectContext.set(objectContextMap);
    >>
    >>
    >> --------------------------------------------------------------------------------------
    >> 2009/9/14 Andrey Razumovsky <razumovsky.andre..mail.com>:
    >> > 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
    >> >
    >>
    >
    >
    >
    > --
    > Andrey
    >



    This archive was generated by hypermail 2.0.0 : Tue Sep 15 2009 - 11:19:38 EDT