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 }