View Javadoc

1   /*
2    *   Copyright 2004 The Apache Software Foundation
3    *
4    *   Licensed under the Apache License, Version 2.0 (the "License");
5    *   you may not use this file except in compliance with the License.
6    *   You may obtain a copy of the License at
7    *
8    *       http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *   Unless required by applicable law or agreed to in writing, software
11   *   distributed under the License is distributed on an "AS IS" BASIS,
12   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *   See the License for the specific language governing permissions and
14   *   limitations under the License.
15   *
16   */
17  package org.apache.ldap.server.schema;
18  
19  
20  import java.util.ArrayList;
21  import java.util.Collections;
22  import java.util.Hashtable;
23  import java.util.Iterator;
24  import java.util.List;
25  
26  import javax.naming.NamingException;
27  
28  import org.apache.ldap.server.schema.bootstrap.BootstrapOidRegistry;
29  
30  
31  /***
32   * Default OID registry implementation used to resolve a schema object OID 
33   * to a name and vice-versa.
34   * 
35   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
36   * @version $Rev: 328545 $
37   */
38  public class GlobalOidRegistry implements OidRegistry
39  { 
40      /*** Maps OID to a name or a list of names if more than one name exists */
41      private Hashtable byOid = new Hashtable();
42  
43      /*** Maps several names to an OID */
44      private Hashtable byName = new Hashtable();
45  
46      /*** Default OidRegistryMonitor */
47      private OidRegistryMonitor monitor = new OidRegistryMonitorAdapter();
48  
49      /*** the underlying bootstrap registry to delegate on misses to */
50      private BootstrapOidRegistry bootstrap;
51  
52  
53      // ------------------------------------------------------------------------
54      // C O N S T R U C T O R S
55      // ------------------------------------------------------------------------
56  
57  
58      /***
59       * Creates a default OidRegistry by initializing the map and the montior.
60       */
61      public GlobalOidRegistry( BootstrapOidRegistry bootstrap )
62      {
63          this.bootstrap = bootstrap;
64  
65          if ( this.bootstrap == null )
66          {
67              throw new NullPointerException( "the bootstrap registry cannot be null" ) ;
68          }
69      }
70  
71  
72  
73  
74      /***
75       * Gets the monitor.
76       *
77       * @return the monitor
78       */
79      OidRegistryMonitor getMonitor()
80      {
81          return monitor;
82      }
83  
84  
85      /***
86       * Sets the monitor.
87       *
88       * @param monitor monitor to set.
89       */
90      void setMonitor( OidRegistryMonitor monitor )
91      {
92          this.monitor = monitor;
93      }
94  
95  
96      // ------------------------------------------------------------------------
97      // Service Methods
98      // ------------------------------------------------------------------------
99  
100 
101     /***
102      * @see OidRegistry#getOid(String)
103      */
104     public String getOid( String name ) throws NamingException
105     {
106         if ( name == null )
107         {
108             throw new NamingException( "name should not be null" );
109         }
110 
111         /* If name is an OID than we return it back since inherently the
112          * OID is another name for the object referred to by OID and the
113          * caller does not know that the argument is an OID String.
114          */
115         if ( Character.isDigit( name.charAt( 0 ) ) )
116         {
117             monitor.getOidWithOid( name );
118             return name;
119         }
120 
121         // If name is mapped to a OID already return OID
122 
123         if ( byName.containsKey( name ) )
124         {
125             String oid = ( String ) byName.get( name );
126             monitor.oidResolved( name, oid );
127             return oid;
128         }
129 
130         if ( bootstrap.hasOid( name ) )
131         {
132             String oid = bootstrap.getOid( name );
133             monitor.oidResolved( name, oid );
134             return oid;
135         }
136 
137         /*
138          * As a last resort we check if name is not normalized and if the
139          * normalized version used as a key returns an OID.  If the normalized
140          * name works add the normalized name as a key with its OID to the
141          * byName lookup.  BTW these normalized versions of the key are not
142          * returned on a getNameSet.
143          */
144         String lowerCase = name.trim().toLowerCase();
145         if ( ! name.equals( lowerCase ) )
146 		{
147 			if ( byName.containsKey( lowerCase ) )
148 	        {
149 	            String oid = ( String ) byName.get( lowerCase );
150 	            monitor.oidResolved( name, lowerCase, oid );
151 
152 	            // We expect to see this version of the key again so we add it
153 	            byName.put( name, oid );
154                 return oid;
155 	        }
156 			
157 			/*
158 			 * Some LDAP servers (MS Active Directory) tend to use some of the
159 			 * bootstrap oid names as all caps, like OU. This should resolve that.
160 			 * Lets stash this in the byName if we find it.
161 			 */
162 			
163 			if ( bootstrap.hasOid( lowerCase) )
164 			{
165 	            String oid = bootstrap.getOid( name );
166                 monitor.oidResolved( name, oid );
167 
168 	            // We expect to see this version of the key again so we add it
169                 byName.put( name, oid );
170                 return oid;
171 			}
172 		}
173 
174         String msg = "OID for name '" + name + "' was not " + "found within the OID registry";
175         NamingException fault = new NamingException ( msg );
176         monitor.oidResolutionFailed( name, fault );
177         throw fault;
178     }
179 
180 
181     /***
182      * @see OidRegistry#hasOid(String)
183      */
184     public boolean hasOid( String name )
185     {
186         // check first with non-normalized name
187         if ( this.byName.containsKey( name ) || this.byOid.containsKey( name ) )
188         {
189             return true;
190         }
191 
192         // check next with non-normalized name on the bootstrap registry
193         if ( this.bootstrap.hasOid( name ) )
194         {
195             return true;
196         }
197 
198         /*
199         * As a last resort we check if name is not normalized and if the
200         * normalized version used as a key returns an OID.  If the normalized
201         * name works add the normalized name as a key with its OID to the
202         * byName lookup.  BTW these normalized versions of the key are not
203         * returned on a getNameSet.
204         */
205         String lowerCase = name.trim().toLowerCase();
206         if ( ! name.equals( lowerCase ) )
207 		{
208 			if ( byName.containsKey( lowerCase ) )
209 	        {
210 	            String oid = ( String ) byName.get( lowerCase );
211 	            monitor.oidResolved( name, lowerCase, oid );
212 
213 	            // We expect to see this version of the key again so we add it
214 	            byName.put( name, oid );
215                 return true;
216 	        }
217 
218 			/*
219 			 * Some LDAP servers (MS Active Directory) tend to use some of the
220 			 * bootstrap oid names as all caps, like OU. This should resolve that.
221 			 * Lets stash this in the byName if we find it.
222 			 */
223 			if ( bootstrap.hasOid( lowerCase) )
224 			{
225                 return true;
226 			}
227 		}
228 
229         return false;
230     }
231 
232 
233     /***
234      * @see OidRegistry#getPrimaryName(String)
235      */
236     public String getPrimaryName( String oid ) throws NamingException
237     {
238         Object value = byOid.get( oid );
239         
240         if ( null == value )
241         {
242             String msg = "OID '" + oid + "' was not found within the OID registry";
243 
244             NamingException fault = new NamingException ( msg );
245 
246             monitor.oidDoesNotExist( oid, fault );
247 
248             throw fault;
249         }
250         
251         if ( value instanceof String )
252         {
253             monitor.nameResolved( oid, ( String ) value );
254 
255             return ( String ) value;
256         }
257         
258         String name = ( String ) ( ( List ) value ).get( 0 );
259 
260         monitor.nameResolved( oid, name );
261 
262         return name;
263     }
264 
265 
266     /***
267      * @see OidRegistry#getNameSet(String)
268      */
269     public List getNameSet( String oid ) throws NamingException
270     {
271         Object value = this.byOid.get( oid );
272         
273         if ( null == value )
274         {
275             value = this.bootstrap.getNameSet( oid );
276         }
277 
278         if ( null == value )
279         {
280             String msg = "OID '" + oid + "' was not found within the OID registry";
281 
282             NamingException fault = new NamingException ( msg );
283 
284             monitor.oidDoesNotExist( oid, fault );
285 
286             throw fault;
287         }
288         
289         if ( value instanceof String )
290         {
291             List list = Collections.singletonList( value );
292 
293             monitor.namesResolved( oid, list );
294 
295             return list;
296         }
297         
298         monitor.namesResolved( oid, ( List ) value );
299 
300         return ( List ) value;
301     }
302 
303 
304     /***
305      * @see OidRegistry#list()
306      */
307     public Iterator list()
308     {
309         return Collections.unmodifiableSet( byOid.keySet() ).iterator();
310     }
311 
312 
313     /***
314      * @see OidRegistry#register(String, String)
315      */
316     public void register( String name, String oid )
317     {
318         if ( ! Character.isDigit( oid.charAt( 0 ) ) )
319         {
320             throw new RuntimeException( "Swap the parameter order: the oid " +
321                 "does not start with a digit!" );
322         }
323 
324         /*
325          * Add the entry for the given name as is and its lowercased version if
326          * the lower cased name is different from the given name name.  
327          */
328         String lowerCase = name.toLowerCase();
329 
330         if ( ! lowerCase.equals( name ) )
331         {
332             byName.put( lowerCase, oid );
333         }
334         
335         // Put both the name and the oid as names
336         byName.put( name, oid );
337 
338         byName.put( oid, oid );
339         
340         /*
341          * Update OID Map
342          * 
343          * 1). Check if we already have a value[s] stored
344          *      1a). Value is a single value and is a String
345          *          Replace value with list containing old and new values
346          *      1b). More than one value stored in a list
347          *          Add new value to the list
348          * 2). If we do not have a value then we just add it as a String
349          */
350         Object value = null;
351 
352         if ( ! byOid.containsKey( oid ) )
353         {
354             value = name;
355         }
356         else 
357         {
358             ArrayList list = null;
359 
360             value = byOid.get( oid );
361             
362             if ( value instanceof String )
363             {
364                 String existingName = ( String ) value;
365                 
366                 // if the existing name is already there we don't readd it
367                 if ( existingName.equalsIgnoreCase( name ) )
368                 {
369                     return;
370                 }
371                 
372                 list = new ArrayList();
373 
374                 list.add( value );
375 
376                 value = list;
377             }
378             else if ( value instanceof ArrayList )
379             {
380                 list = ( ArrayList ) value;
381                 
382                 for ( int ii = 0; ii < list.size(); ii++ )
383                 {
384                     // One form or another of the name already exists in list
385                     if ( ! name.equalsIgnoreCase( ( String ) list.get( ii ) ) )
386                     {
387                         return;
388                     }
389                 }
390                 
391                 list.add( name );
392             }
393         }
394 
395         byOid.put( oid, value );
396 
397         monitor.registered( name, oid );
398     }
399 }
400