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: 264732 $
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 
119             return name;
120         }
121 
122         // If name is mapped to a OID already return OID
123 
124         if ( byName.containsKey( name ) )
125         {
126             String oid = ( String ) byName.get( name );
127 
128             monitor.oidResolved( name, oid );
129 
130             return oid;
131         }
132 
133         if ( bootstrap.hasOid( name ) )
134         {
135             String oid = bootstrap.getOid( name );
136 
137             monitor.oidResolved( name, oid );
138 
139             return oid;
140         }
141 
142         /*
143          * As a last resort we check if name is not normalized and if the
144          * normalized version used as a key returns an OID.  If the normalized
145          * name works add the normalized name as a key with its OID to the
146          * byName lookup.  BTW these normalized versions of the key are not
147          * returned on a getNameSet.
148          */
149         String lowerCase = name.trim().toLowerCase();
150 
151         if ( ! name.equals( lowerCase ) )
152 		{
153 			if ( byName.containsKey( lowerCase ) )
154 	        {
155 	            String oid = ( String ) byName.get( lowerCase );
156 
157 	            monitor.oidResolved( name, lowerCase, oid );
158 	
159 	            // We expect to see this version of the key again so we add it
160 
161 	            byName.put( name, oid );
162 
163                 return oid;
164 	        }
165 			
166 			/*
167 			 * Some LDAP servers (MS Active Directory) tend to use some of the
168 			 * bootstrap oid names as all caps, like OU. This should resolve that.
169 			 * Lets stash this in the byName if we find it.
170 			 */
171 			
172 			if ( bootstrap.hasOid( lowerCase) )
173 			{
174 	            String oid = bootstrap.getOid( name );
175 
176                 monitor.oidResolved( name, oid );
177 
178 	            // We expect to see this version of the key again so we add it
179 
180                 byName.put( name, oid );
181 
182                 return oid;
183 			}
184 		}
185 
186         String msg = "OID for name '" + name + "' was not " + "found within the OID registry";
187 
188         NamingException fault = new NamingException ( msg );
189 
190         monitor.oidResolutionFailed( name, fault );
191 
192         throw fault;
193     }
194 
195 
196     /***
197      * @see OidRegistry#hasOid(String)
198      */
199     public boolean hasOid( String name )
200     {
201         return this.byName.containsKey( name ) || this.byOid.containsKey( name )  ||
202                this.bootstrap.hasOid( name );
203     }
204 
205 
206     /***
207      * @see OidRegistry#getPrimaryName(String)
208      */
209     public String getPrimaryName( String oid ) throws NamingException
210     {
211         Object value = byOid.get( oid );
212         
213         if ( null == value )
214         {
215             String msg = "OID '" + oid + "' was not found within the OID registry";
216 
217             NamingException fault = new NamingException ( msg );
218 
219             monitor.oidDoesNotExist( oid, fault );
220 
221             throw fault;
222         }
223         
224         if ( value instanceof String )
225         {
226             monitor.nameResolved( oid, ( String ) value );
227 
228             return ( String ) value;
229         }
230         
231         String name = ( String ) ( ( List ) value ).get( 0 );
232 
233         monitor.nameResolved( oid, name );
234 
235         return name;
236     }
237 
238 
239     /***
240      * @see OidRegistry#getNameSet(String)
241      */
242     public List getNameSet( String oid ) throws NamingException
243     {
244         Object value = byOid.get( oid );
245         
246         if ( null == value )
247         {
248             String msg = "OID '" + oid + "' was not found within the OID registry";
249 
250             NamingException fault = new NamingException ( msg );
251 
252             monitor.oidDoesNotExist( oid, fault );
253 
254             throw fault;
255         }
256         
257         if ( value instanceof String )
258         {
259             List list = Collections.singletonList( value );
260 
261             monitor.namesResolved( oid, list );
262 
263             return list;
264         }
265         
266         monitor.namesResolved( oid, ( List ) value );
267 
268         return ( List ) value;
269     }
270 
271 
272     /***
273      * @see OidRegistry#list()
274      */
275     public Iterator list()
276     {
277         return Collections.unmodifiableSet( byOid.keySet() ).iterator();
278     }
279 
280 
281     /***
282      * @see OidRegistry#register(String, String)
283      */
284     public void register( String name, String oid )
285     {
286         if ( ! Character.isDigit( oid.charAt( 0 ) ) )
287         {
288             throw new RuntimeException( "Swap the parameter order: the oid " +
289                 "does not start with a digit!" );
290         }
291 
292         /*
293          * Add the entry for the given name as is and its lowercased version if
294          * the lower cased name is different from the given name name.  
295          */
296         String lowerCase = name.toLowerCase();
297 
298         if ( ! lowerCase.equals( name ) )
299         {
300             byName.put( lowerCase, oid );
301         }
302         
303         // Put both the name and the oid as names
304         byName.put( name, oid );
305 
306         byName.put( oid, oid );
307         
308         /*
309          * Update OID Map
310          * 
311          * 1). Check if we already have a value[s] stored
312          *      1a). Value is a single value and is a String
313          *          Replace value with list containing old and new values
314          *      1b). More than one value stored in a list
315          *          Add new value to the list
316          * 2). If we do not have a value then we just add it as a String
317          */
318         Object value = null;
319 
320         if ( ! byOid.containsKey( oid ) )
321         {
322             value = name;
323         }
324         else 
325         {
326             ArrayList list = null;
327 
328             value = byOid.get( oid );
329             
330             if ( value instanceof String )
331             {
332                 String existingName = ( String ) value;
333                 
334                 // if the existing name is already there we don't readd it
335                 if ( existingName.equalsIgnoreCase( name ) )
336                 {
337                     return;
338                 }
339                 
340                 list = new ArrayList();
341 
342                 list.add( value );
343 
344                 value = list;
345             }
346             else if ( value instanceof ArrayList )
347             {
348                 list = ( ArrayList ) value;
349                 
350                 for ( int ii = 0; ii < list.size(); ii++ )
351                 {
352                     // One form or another of the name already exists in list
353                     if ( ! name.equalsIgnoreCase( ( String ) list.get( ii ) ) )
354                     {
355                         return;
356                     }
357                 }
358                 
359                 list.add( name );
360             }
361         }
362 
363         byOid.put( oid, value );
364 
365         monitor.registered( name, oid );
366     }
367 }
368