Re: getThreadObjectContext with domain parameter - code -

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

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

    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 : Mon Sep 14 2009 - 14:24:15 EDT