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