1   // ========================================================================
2   // $Id: NamingEntry.java 2952 2008-06-10 04:00:02Z gregw $
3   // Copyright 2006 Mort Bay Consulting Pty. Ltd.
4   // ------------------------------------------------------------------------
5   // Licensed under the Apache License, Version 2.0 (the "License");
6   // you may not use this file except in compliance with the License.
7   // You may obtain a copy of the License at 
8   // http://www.apache.org/licenses/LICENSE-2.0
9   // Unless required by applicable law or agreed to in writing, software
10  // distributed under the License is distributed on an "AS IS" BASIS,
11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  // See the License for the specific language governing permissions and
13  // limitations under the License.
14  // ========================================================================
15  
16  package org.mortbay.jetty.plus.naming;
17  
18  import java.util.ArrayList;
19  import java.util.List;
20  
21  import javax.naming.Binding;
22  import javax.naming.Context;
23  import javax.naming.InitialContext;
24  import javax.naming.LinkRef;
25  import javax.naming.Name;
26  import javax.naming.NameNotFoundException;
27  import javax.naming.NameParser;
28  import javax.naming.NamingEnumeration;
29  import javax.naming.NamingException;
30  
31  import org.mortbay.log.Log;
32  import org.mortbay.naming.NamingUtil;
33  
34  
35  
36  /**
37   * NamingEntry
38   *
39   * Base class for all jndi related entities. Instances of
40   * subclasses of this class are declared in jetty.xml or in a 
41   * webapp's WEB-INF/jetty-env.xml file.
42   *
43   * NOTE: that all NamingEntries will be bound in a single namespace.
44   *  The "global" level is just in the top level context. The "local"
45   *  level is a context specific to a webapp.
46   */
47  public abstract class NamingEntry
48  {
49      public static final int SCOPE_CONTAINER = 0;
50      public static final int SCOPE_WEBAPP = 1;
51      protected String jndiName;  //the name representing the object associated with the NamingEntry
52      protected Object objectToBind; //the object associated with the NamingEntry
53      protected String absoluteObjectNameString; //the absolute name of the object
54      protected String namingEntryNameString; //the name of the NamingEntry relative to the context it is stored in
55      protected String objectNameString; //the name of the object relative to the context it is stored in
56      protected Context context; //the context in which both Naming Entry and object are saved
57      protected boolean isContainerScope;
58      protected static ThreadLocal scope = new ThreadLocal();
59      
60      public static void setScope (int scopeType)
61      {
62          scope.set(new Integer(scopeType));
63      }
64      
65      public static int getScope ()
66      {
67          Integer val = (Integer)scope.get();
68          return (val == null?SCOPE_CONTAINER:val.intValue());
69      }
70      
71     
72      public static Name makeNamingEntryName (NameParser parser, String jndiName)
73      throws NamingException
74      {
75          if (jndiName==null || parser==null)
76              return null;
77          
78          Name name = parser.parse("");
79          name.add(jndiName);
80          String lastAtom = (String)name.remove(name.size()-1);
81          lastAtom="__"+lastAtom;
82          name.add(lastAtom);
83          return name;
84      }
85      
86      
87      /** 
88       * Create a NamingEntry. 
89       * A NamingEntry is a name associated with a value which can later
90       * be looked up in JNDI by a webapp.
91       * 
92       * We create the NamingEntry and put it into JNDI where it can
93       * be linked to the webapp's env-entry, resource-ref etc entries.
94       * 
95       * @param jndiName the name of the object which will eventually be in java:comp/env
96       * @param object the object to be bound
97       * @throws NamingException
98       */
99      public NamingEntry (String jndiName, Object object)
100     throws NamingException
101     {
102         this.jndiName = jndiName;
103         this.objectToBind = object;
104         
105         //if a threadlocal is set indicating we are inside a
106         //webapp, then save naming entries to the webapp's
107         //local context instead of the container's global context
108         isContainerScope=(getScope()==SCOPE_CONTAINER);
109         InitialContext icontext = new InitialContext();
110         if (isContainerScope)
111             context = icontext;
112         else
113             context = (Context)icontext.lookup("java:comp/env");
114         save(); 
115     }
116 
117     
118     
119     /**
120      * Add a java:comp/env binding for the object represented by
121      * this NamingEntry
122      * @throws NamingException
123      */
124     /*
125     public void bindToENC ()
126     throws NamingException
127     {
128         if (isLocal())
129         {
130             //don't bind local scope naming entries as they are already bound to java:comp/env
131         }
132         else if (isGlobal())
133         {
134             InitialContext ic = new InitialContext();
135             Context env = (Context)ic.lookup("java:comp/env");
136             Log.debug("Binding java:comp/env/"+getJndiName()+" to "+absoluteObjectNameString);
137             NamingUtil.bind(env, getJndiName(), new LinkRef(absoluteObjectNameString));
138         }
139     }
140     */
141     
142     /**
143      * Add a java:comp/env binding for the object represented by this NamingEntry,
144      * but bind it as the name supplied
145      * @throws NamingException
146      */
147     public void bindToENC(String localName)
148     throws NamingException
149     {
150         
151         
152         if (localName.equals(jndiName) && isLocal())
153         {
154             Log.warn("Already bound "+localName+" to java:comp/env with "+absoluteObjectNameString);
155             return; //name already bound to local
156         }
157         
158         InitialContext ic = new InitialContext();
159         Context env = (Context)ic.lookup("java:comp/env");
160         Log.debug("Binding java:comp/env/"+localName+" to "+absoluteObjectNameString);
161         NamingUtil.bind(env, localName, new LinkRef(absoluteObjectNameString));
162     }
163     
164     /**
165      * Unbind this NamingEntry from a java:comp/env
166      */
167     public void unbindENC ()
168     {
169         try
170         {
171             InitialContext ic = new InitialContext();
172             Context env = (Context)ic.lookup("java:comp/env");
173             Log.debug("Unbinding java:comp/env/"+getJndiName());
174             env.unbind(getJndiName());
175         }
176         catch (NamingException e)
177         {
178             Log.warn(e);
179         }
180     }
181     
182     /**
183      * Unbind this NamingEntry entirely
184      */
185     public void release ()
186     {
187         try
188         {
189             context.unbind(objectNameString);
190             context.unbind(namingEntryNameString);
191             this.absoluteObjectNameString=null;
192             this.jndiName=null;
193             this.namingEntryNameString=null;
194             this.objectNameString=null;
195             this.objectToBind=null;
196             this.context=null;
197         }
198         catch (NamingException e)
199         {
200             Log.warn(e);
201         }
202     }
203     
204     /**
205      * Get the unique name of the object
206      * @return
207      */
208     public String getJndiName ()
209     {
210         return this.jndiName;
211     }
212     
213     /**
214      * Get the object that is to be bound
215      * @return
216      */
217     public Object getObjectToBind()
218     throws NamingException
219     {   
220         return this.objectToBind;
221     }
222     
223     /**
224      * Check if this naming entry was global or locally scoped to a webapp
225      * @return true if naming entry was bound at global scope, false otherwise
226      */
227     public boolean isGlobal ()
228     {
229         return this.isContainerScope;
230     }
231     
232     public boolean isLocal()
233     {
234         return !this.isContainerScope;
235     }
236     
237  
238  
239     
240     /**
241      * Save the NamingEntry for later use.
242      * 
243      * Saving is done by binding the NamingEntry
244      * itself, and the value it represents into
245      * JNDI. In this way, we can link to the
246      * value it represents later, but also
247      * still retrieve the NamingEntry itself too.
248      * 
249      * The object is bound at the jndiName passed in.
250      * This NamingEntry is bound at __jndiName.
251      * 
252      * eg
253      * 
254      * /jdbc/foo   : DataSource
255      * /jdbc/__foo : NamingEntry
256      * 
257      * @throws NamingException
258      */
259     protected void save ()
260     throws NamingException
261     {
262         NameParser parser = context.getNameParser("");
263         Name contextName = parser.parse(context.getNameInNamespace());
264         
265         //save the NamingEntry itself so it can be accessed later       
266         Name namingEntryName = makeNamingEntryName(parser, jndiName);
267         namingEntryNameString = namingEntryName.toString();
268         NamingUtil.bind(context, namingEntryNameString, this);
269         Log.debug("Bound "+(isGlobal()?"":"java:")+namingEntryName.addAll(0,contextName));
270         
271         //put the Object into JNDI so it can be linked to later  
272         Name objectName = parser.parse(getJndiName());
273         objectNameString = objectName.toString();
274         NamingUtil.bind(context, objectNameString, getObjectToBind());       
275         
276         //remember the full name of the bound object so that it can be used in
277         //link references later
278         Name fullName = objectName.addAll(0,contextName);
279         absoluteObjectNameString = (isContainerScope?"":"java:")+fullName.toString();       
280         Log.debug("Bound "+absoluteObjectNameString);
281     }
282     
283     
284 }