View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.jndi;
20  
21  
22  import java.io.IOException;
23  import java.util.Hashtable;
24  import java.util.Map;
25  import java.util.WeakHashMap;
26  import javax.naming.Context;
27  import javax.naming.Name;
28  import javax.naming.NameParser;
29  import javax.naming.Reference;
30  import javax.naming.StringRefAddr;
31  import javax.naming.spi.ObjectFactory;
32  
33  import org.eclipse.jetty.server.handler.ContextHandler;
34  import org.eclipse.jetty.util.log.Logger;
35  
36  
37  
38  /**
39   * ContextFactory.java
40   *
41   * This is an object factory that produces a jndi naming
42   * context based on a classloader.
43   *
44   *  It is used for the java:comp context.
45   *
46   *  This object factory is bound at java:comp. When a
47   *  lookup arrives for java:comp,  this object factory
48   *  is invoked and will return a context specific to
49   *  the caller's environment (so producing the java:comp/env
50   *  specific to a webapp).
51   *
52   *  The context selected is based on classloaders. First
53   *  we try looking in at the classloader that is associated
54   *  with the current webapp context (if there is one). If
55   *  not, we use the thread context classloader.
56   *
57   * Created: Fri Jun 27 09:26:40 2003
58   *
59   *
60   *
61   */
62  public class ContextFactory implements ObjectFactory
63  {
64      private static Logger __log = NamingUtil.__log;
65  
66      /**
67       * Map of classloaders to contexts.
68       */
69      private static final WeakHashMap __contextMap = new WeakHashMap();
70  
71      /**
72       * Threadlocal for injecting a context to use
73       * instead of looking up the map.
74       */
75      private static final ThreadLocal __threadContext = new ThreadLocal();
76  
77  
78      /**
79       * Find or create a context which pertains to a classloader.
80       *
81       * We use either the classloader for the current ContextHandler if
82       * we are handling a request, OR we use the thread context classloader
83       * if we are not processing a request.
84       * @see javax.naming.spi.ObjectFactory#getObjectInstance(java.lang.Object, javax.naming.Name, javax.naming.Context, java.util.Hashtable)
85       */
86      public Object getObjectInstance (Object obj,
87                                       Name name,
88                                       Context nameCtx,
89                                       Hashtable env)
90          throws Exception
91      {
92          //First, see if we have had a context injected into us to use.
93          Context ctx = (Context)__threadContext.get();
94          if (ctx != null)
95          {
96              if(__log.isDebugEnabled()) __log.debug("Using the Context that is bound on the thread");
97              return ctx;
98          }
99  
100         ClassLoader loader = null;
101 
102         loader = Thread.currentThread().getContextClassLoader();
103         if (__log.isDebugEnabled() && loader != null) __log.debug("Using thread context classloader");
104 
105         if (loader == null && ContextHandler.getCurrentContext() != null)
106         {
107             loader = ContextHandler.getCurrentContext().getContextHandler().getClassLoader();
108             if (__log.isDebugEnabled() && loader != null) __log.debug("Using classloader of current org.eclipse.jetty.server.handler.ContextHandler");
109         }
110 
111         //Get the context matching the classloader
112         ctx = (Context)__contextMap.get(loader);
113 
114         //The map does not contain an entry for this classloader
115         if (ctx == null)
116         {
117             //Didn't find a context to match, make one
118             Reference ref = (Reference)obj;
119             StringRefAddr parserAddr = (StringRefAddr)ref.get("parser");
120             String parserClassName = (parserAddr==null?null:(String)parserAddr.getContent());
121             NameParser parser = (NameParser)(parserClassName==null?null:loader.loadClass(parserClassName).newInstance());
122 
123             ctx = new NamingContext (env,
124                                      name.get(0),
125                                      (NamingContext)nameCtx,
126                                      parser);
127             if(__log.isDebugEnabled())__log.debug("Made context "+name.get(0)+" for classloader: "+loader);
128             __contextMap.put (loader, ctx);
129         }
130 
131         return ctx;
132     }
133 
134   
135 
136 
137     /**
138      * Associate the given Context with the current thread.
139      * resetComponentContext method should be called to reset the context.
140      * @param ctx the context to associate to the current thread.
141      * @return the previous context associated on the thread (can be null)
142      */
143     public static Context setComponentContext(final Context ctx)
144     {
145         Context previous = (Context)__threadContext.get();
146         __threadContext.set(ctx);
147         return previous;
148     }
149 
150     /**
151      * Set back the context with the given value.
152      * Don't return the previous context, use setComponentContext() method for this.
153      * @param ctx the context to associate to the current thread.
154      */
155     public static void resetComponentContext(final Context ctx)
156     {
157         __threadContext.set(ctx);
158     }
159 
160     public static void dump(Appendable out, String indent) throws IOException
161     {
162         out.append("o.e.j.jndi.ContextFactory@").append(Long.toHexString(__contextMap.hashCode())).append("\n");
163         int size=__contextMap.size();
164         int i=0;
165         for (Map.Entry<ClassLoader,NamingContext> entry : ((Map<ClassLoader,NamingContext>)__contextMap).entrySet())
166         {
167             boolean last=++i==size;
168             ClassLoader loader=entry.getKey();
169             out.append(indent).append(" +- ").append(loader.getClass().getSimpleName()).append("@").append(Long.toHexString(loader.hashCode())).append(": ");
170 
171             NamingContext context = entry.getValue();
172             context.dump(out,indent+(last?"    ":" |  "));
173         }
174     }
175 
176 }