KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > naming > ExternalContext


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.naming;
23
24 import java.io.IOException JavaDoc;
25 import java.io.InputStream JavaDoc;
26 import java.io.Serializable JavaDoc;
27 import java.lang.reflect.Constructor JavaDoc;
28 import java.lang.reflect.InvocationHandler JavaDoc;
29 import java.lang.reflect.InvocationTargetException JavaDoc;
30 import java.lang.reflect.Method JavaDoc;
31 import java.lang.reflect.Proxy JavaDoc;
32 import java.net.URL JavaDoc;
33 import java.util.Hashtable JavaDoc;
34 import java.util.Properties JavaDoc;
35
36 import javax.naming.CompositeName JavaDoc;
37 import javax.naming.Context JavaDoc;
38 import javax.naming.InitialContext JavaDoc;
39 import javax.naming.Name JavaDoc;
40 import javax.naming.NamingException JavaDoc;
41 import javax.naming.RefAddr JavaDoc;
42 import javax.naming.Reference JavaDoc;
43 import javax.naming.Referenceable JavaDoc;
44 import javax.naming.ldap.Control JavaDoc;
45 import javax.naming.spi.ObjectFactory JavaDoc;
46
47 import org.jboss.system.ServiceMBeanSupport;
48
49 /**
50  * A MBean that binds an arbitrary InitialContext into the JBoss default
51  * InitialContext as a Reference. If RemoteAccess is enabled, the reference
52  * is a Serializable object that is capable of creating the InitialContext
53  * remotely. If RemoteAccess if false, the reference is to a nonserializable object
54  * that can only be used from within this VM.
55  *
56  * @jmx:mbean extends="org.jboss.system.ServiceMBean"
57  *
58  * @see org.jboss.naming.NonSerializableFactory
59  *
60  * @version <tt>$Revision: 37459 $</tt>
61  * @author Scott.Stark@jboss.org
62  * @author <a HREF="mailto:jason@planet57.com">Jason Dillon</a>
63  */

64 public class ExternalContext
65    extends ServiceMBeanSupport
66    implements ExternalContextMBean
67 {
68    private boolean remoteAccess;
69    private SerializableInitialContext contextInfo = new SerializableInitialContext();
70
71    /**
72     * No-args constructor for JMX.
73     */

74    public ExternalContext()
75    {
76       super();
77    }
78
79    public ExternalContext(String JavaDoc jndiName, String JavaDoc contextPropsURL)
80       throws IOException JavaDoc, NamingException JavaDoc
81    {
82       setJndiName(jndiName);
83       setPropertiesURL(contextPropsURL);
84    }
85
86    /**
87     * Set the jndi name under which the external context is bound.
88     *
89     * @jmx:managed-attribute
90     */

91    public String JavaDoc getJndiName()
92    {
93       return contextInfo.getJndiName();
94    }
95
96    /**
97     * Set the jndi name under which the external context is bound.
98     *
99     * @jmx:managed-attribute
100     */

101    public void setJndiName(String JavaDoc jndiName) throws NamingException JavaDoc
102    {
103       contextInfo.setJndiName(jndiName);
104       if( super.getState() == STARTED )
105       {
106          unbind(jndiName);
107          try
108          {
109             rebind();
110          }
111          catch(Exception JavaDoc e)
112          {
113             NamingException JavaDoc ne = new NamingException JavaDoc("Failed to update jndiName");
114             ne.setRootCause(e);
115             throw ne;
116          }
117       }
118    }
119
120    /**
121     * @jmx:managed-attribute
122     */

123    public boolean getRemoteAccess()
124    {
125       return remoteAccess;
126    }
127    
128    /**
129     * @jmx:managed-attribute
130     */

131    public void setRemoteAccess(final boolean remoteAccess)
132    {
133       this.remoteAccess = remoteAccess;
134    }
135    
136    /**
137     * @jmx:managed-attribute
138     */

139    public boolean getCacheContext()
140    {
141       return contextInfo.getCacheContext();
142    }
143    
144    /**
145     * @jmx:managed-attribute
146     */

147    public void setCacheContext(boolean cacheContext)
148    {
149       contextInfo.setCacheContext(cacheContext);
150    }
151
152    /**
153     * Get the class name of the InitialContext implementation to
154     * use. Should be one of:
155     * <ul>
156     * <li>javax.naming.InitialContext
157     * <li>javax.naming.directory.InitialDirContext
158     * <li>javax.naming.ldap.InitialLdapContext
159     * </ul>
160     *
161     * @jmx:managed-attribute
162     *
163     * @return the classname of the InitialContext to use
164     */

165    public String JavaDoc getInitialContext()
166    {
167       return contextInfo.getInitialContext();
168    }
169
170    /**
171     * Set the class name of the InitialContext implementation to
172     * use. Should be one of:
173     * <ul>
174     * <li>javax.naming.InitialContext
175     * <li>javax.naming.directory.InitialDirContext
176     * <li>javax.naming.ldap.InitialLdapContext
177     * </ul>
178     *
179     * @jmx:managed-attribute
180     *
181     * @param contextClass, the classname of the InitialContext to use
182     */

183    public void setInitialContext(String JavaDoc className) throws ClassNotFoundException JavaDoc
184    {
185       contextInfo.loadClass(className);
186    }
187
188    /**
189     * Set the InitialContex class environment properties from the given URL.
190     *
191     * @jmx:managed-attribute
192     */

193    public void setPropertiesURL(String JavaDoc contextPropsURL) throws IOException JavaDoc
194    {
195       contextInfo.loadProperties(contextPropsURL);
196    }
197
198    /**
199     * Set the InitialContex class environment properties.
200     *
201     * @jmx:managed-attribute
202     */

203    public void setProperties(final Properties JavaDoc props) throws IOException JavaDoc
204    {
205       contextInfo.setProperties(props);
206    }
207
208    /**
209     * Get the InitialContex class environment properties.
210     *
211     * @jmx:managed-attribute
212     */

213    public Properties JavaDoc getProperties() throws IOException JavaDoc
214    {
215       return contextInfo.getProperties();
216    }
217    
218    /**
219     * Start the service by binding the external context into the
220     * JBoss InitialContext.
221     */

222    protected void startService() throws Exception JavaDoc
223    {
224       rebind();
225    }
226
227    /**
228     * Stop the service by unbinding the external context into the
229     * JBoss InitialContext.
230     */

231    protected void stopService() throws Exception JavaDoc
232    {
233       if( contextInfo.getCacheContext() )
234          unbind(contextInfo.getJndiName());
235    }
236
237    private static Context JavaDoc createContext(Context JavaDoc rootContext, Name JavaDoc name) throws NamingException JavaDoc
238    {
239       Context JavaDoc subctx = rootContext;
240       for(int n = 0; n < name.size(); n ++)
241       {
242          String JavaDoc atom = name.get(n);
243          try
244          {
245             Object JavaDoc obj = subctx.lookup(atom);
246             subctx = (Context JavaDoc) obj;
247          }
248          catch(NamingException JavaDoc e)
249          {
250             // No binding exists, create a subcontext
251
subctx = subctx.createSubcontext(atom);
252          }
253       }
254
255       return subctx;
256    }
257
258    private void rebind() throws Exception JavaDoc
259    {
260       Context JavaDoc ctx = contextInfo.newContext();
261       Context JavaDoc rootCtx = (Context JavaDoc) new InitialContext JavaDoc();
262
263       log.debug("ctx="+ctx+", env="+ctx.getEnvironment());
264       
265       // Get the parent context into which we are to bind
266
String JavaDoc jndiName = contextInfo.getJndiName();
267       Name JavaDoc fullName = rootCtx.getNameParser("").parse(jndiName);
268
269       log.debug("fullName="+fullName);
270       
271       Name JavaDoc parentName = fullName;
272       if( fullName.size() > 1 )
273          parentName = fullName.getPrefix(fullName.size()-1);
274       else
275          parentName = new CompositeName JavaDoc();
276       
277       log.debug("parentName="+parentName);
278       
279       Context JavaDoc parentCtx = createContext(rootCtx, parentName);
280       
281       log.debug("parentCtx="+parentCtx);
282       
283       Name JavaDoc atomName = fullName.getSuffix(fullName.size()-1);
284       String JavaDoc atom = atomName.get(0);
285       boolean cacheContext = contextInfo.getCacheContext();
286       
287       if( remoteAccess == true )
288       {
289          // Bind contextInfo as a Referenceable
290
parentCtx.rebind(atom, contextInfo);
291
292          // Cache the context using NonSerializableFactory to avoid creating
293
// more than one context for in VM lookups
294
if( cacheContext == true )
295          {
296             // If cacheContext is true we need to wrap the Context in a
297
// proxy that allows the user to issue close on the lookup
298
// Context without closing the inmemory Context.
299
ctx = CachedContext.createProxyContext(ctx);
300             NonSerializableFactory.rebind(jndiName, ctx);
301          }
302       }
303       else if( cacheContext == true )
304       {
305          // Bind a reference to the extern context using
306
// NonSerializableFactory as the ObjectFactory. The Context must
307
// be wrapped in a proxy that allows the user to issue close on the
308
// lookup Context without closing the inmemory Context.
309

310          Context JavaDoc proxyCtx = CachedContext.createProxyContext(ctx);
311          NonSerializableFactory.rebind(rootCtx, jndiName, proxyCtx);
312       }
313       else
314       {
315          // Bind the contextInfo so that each lookup results in the creation
316
// of a new Context object. The returned Context must be closed
317
// by the user to prevent resource leaks.
318

319          parentCtx.rebind(atom, contextInfo);
320       }
321    }
322
323    private void unbind(String JavaDoc jndiName)
324    {
325       try
326       {
327          Context JavaDoc rootCtx = new InitialContext JavaDoc();
328          Context JavaDoc ctx = (Context JavaDoc) rootCtx.lookup(jndiName);
329          if( ctx != null )
330             ctx.close();
331          rootCtx.unbind(jndiName);
332          NonSerializableFactory.unbind(jndiName);
333       }
334       catch(NamingException JavaDoc e)
335       {
336          log.error("unbind failed", e);
337       }
338    }
339
340    /**
341     * The external InitialContext information class. It acts as the
342     * RefAddr and ObjectFactory for the external IntialContext and can
343     * be marshalled to a remote client.
344     */

345    public static class SerializableInitialContext
346       extends RefAddr JavaDoc
347       implements Referenceable JavaDoc, Serializable JavaDoc, ObjectFactory JavaDoc
348    {
349       private static final long serialVersionUID = -6512260531255770463L;
350       private String JavaDoc jndiName;
351       private Class JavaDoc contextClass = javax.naming.InitialContext JavaDoc.class;
352       private Properties JavaDoc contextProps;
353       private boolean cacheContext = true;
354       private transient Context JavaDoc initialContext;
355
356       public SerializableInitialContext()
357       {
358          this("SerializableInitialContext");
359       }
360       
361       public SerializableInitialContext(String JavaDoc addrType)
362       {
363          super(addrType);
364       }
365
366       public String JavaDoc getJndiName()
367       {
368          return jndiName;
369       }
370       
371       public void setJndiName(final String JavaDoc jndiName)
372       {
373          this.jndiName = jndiName;
374       }
375       
376       public boolean getCacheContext()
377       {
378          return cacheContext;
379       }
380       
381       public void setCacheContext(final boolean cacheContext)
382       {
383          this.cacheContext = cacheContext;
384       }
385       
386       public String JavaDoc getInitialContext()
387       {
388          return contextClass.getName();
389       }
390       
391       public void loadClass(String JavaDoc className) throws ClassNotFoundException JavaDoc
392       {
393          ClassLoader JavaDoc loader = Thread.currentThread().getContextClassLoader();
394          contextClass = loader.loadClass(className);
395       }
396
397       public void setProperties(final Properties JavaDoc props)
398       {
399          contextProps = props;
400       }
401
402       public Properties JavaDoc getProperties()
403       {
404          return contextProps;
405       }
406       
407       public void loadProperties(String JavaDoc contextPropsURL) throws IOException JavaDoc
408       {
409          InputStream JavaDoc is = null;
410          contextProps = new Properties JavaDoc();
411
412          // See if this is a URL we can load
413
try
414          {
415             URL JavaDoc url = new URL JavaDoc(contextPropsURL);
416             is = url.openStream();
417             contextProps.load(is);
418             return;
419          }
420          catch (IOException JavaDoc e)
421          { // Failed, try to locate a classpath resource below
422
is = null;
423          }
424
425          is = Thread.currentThread().getContextClassLoader().getResourceAsStream(contextPropsURL);
426          if( is == null )
427          {
428             throw new IOException JavaDoc("Failed to locate context props as URL or resource:"+contextPropsURL);
429          }
430          contextProps.load(is);
431       }
432
433       Context JavaDoc newContext() throws Exception JavaDoc
434       {
435          // First check the NonSerializableFactory cache
436
initialContext = (Context JavaDoc) NonSerializableFactory.lookup(jndiName);
437          // Create the context from the contextClass and contextProps
438
if( initialContext == null )
439             initialContext = newContext(contextClass, contextProps);
440          return initialContext;
441       }
442
443       static Context JavaDoc newContext(Class JavaDoc contextClass, Properties JavaDoc contextProps)
444          throws Exception JavaDoc
445       {
446          Context JavaDoc ctx = null;
447          try
448          {
449             ctx = newDefaultContext(contextClass, contextProps);
450          }
451          catch(NoSuchMethodException JavaDoc e)
452          {
453             ctx = newLdapContext(contextClass, contextProps);
454          }
455          return ctx;
456       }
457       
458       private static Context JavaDoc newDefaultContext(Class JavaDoc contextClass, Properties JavaDoc contextProps)
459          throws Exception JavaDoc
460       {
461          Context JavaDoc ctx = null;
462          Class JavaDoc[] types = {Hashtable JavaDoc.class};
463          Constructor JavaDoc ctor = contextClass.getConstructor(types);
464          Object JavaDoc[] args = {contextProps};
465          ctx = (Context JavaDoc) ctor.newInstance(args);
466          return ctx;
467       }
468       
469       private static Context JavaDoc newLdapContext(Class JavaDoc contextClass, Properties JavaDoc contextProps)
470          throws Exception JavaDoc
471       {
472          Context JavaDoc ctx = null;
473          Class JavaDoc[] types = {Hashtable JavaDoc.class, Control JavaDoc[].class};
474          Constructor JavaDoc ctor = contextClass.getConstructor(types);
475          Object JavaDoc[] args = {contextProps, null};
476          ctx = (Context JavaDoc) ctor.newInstance(args);
477          return ctx;
478       }
479         
480       public Object JavaDoc getObjectInstance(Object JavaDoc obj, Name JavaDoc name, Context JavaDoc nameCtx, Hashtable JavaDoc environment)
481          throws Exception JavaDoc
482       {
483          Reference JavaDoc ref = (Reference JavaDoc) obj;
484          SerializableInitialContext sic = (SerializableInitialContext) ref.get(0);
485          return sic.newContext();
486       }
487         
488       public Reference JavaDoc getReference() throws NamingException JavaDoc
489       {
490          Reference JavaDoc ref = new Reference JavaDoc(Context JavaDoc.class.getName(), this, this.getClass().getName(), null);
491          return ref;
492       }
493
494       public Object JavaDoc getContent()
495       {
496          return null;
497       }
498    }
499
500    /**
501     * A proxy implementation of Context that simply intercepts the
502     * close() method and ignores it since the underlying Context
503     * object is being maintained in memory.
504     */

505    static class CachedContext implements InvocationHandler JavaDoc
506    {
507       Context JavaDoc externalCtx;
508       
509       CachedContext(Context JavaDoc externalCtx)
510       {
511          this.externalCtx = externalCtx;
512       }
513
514       static Context JavaDoc createProxyContext(Context JavaDoc ctx)
515       {
516          ClassLoader JavaDoc loader = Thread.currentThread().getContextClassLoader();
517          Class JavaDoc[] interfaces = ctx.getClass().getInterfaces();
518          InvocationHandler JavaDoc handler = new CachedContext(ctx);
519          Context JavaDoc proxyCtx = (Context JavaDoc) Proxy.newProxyInstance(loader, interfaces, handler);
520          return proxyCtx;
521       }
522
523       public Object JavaDoc invoke(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc[] args) throws Throwable JavaDoc
524       {
525          Object JavaDoc value = null;
526          if( method.getName().equals("close") )
527          {
528             // We just ignore the close method
529
}
530          else
531          {
532             try
533             {
534                value = method.invoke(externalCtx, args);
535             }
536             catch(InvocationTargetException JavaDoc e)
537             {
538                throw e.getTargetException();
539             }
540          }
541          return value;
542       }
543    }
544 }
545
Popular Tags