View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.server.schema.registries;
21  
22  
23  import java.util.ArrayList;
24  import java.util.Collections;
25  import java.util.HashMap;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Map;
29  
30  import javax.naming.NamingException;
31  import javax.naming.directory.NoSuchAttributeException;
32  
33  import org.slf4j.Logger;
34  import org.slf4j.LoggerFactory;
35  import org.apache.directory.shared.asn1.primitives.OID;
36  import org.apache.directory.shared.ldap.util.StringTools;
37  
38  
39  /**
40   * Default OID registry implementation used to resolve a schema object OID 
41   * to a name and vice-versa.
42   * 
43   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
44   * @version $Rev: 664295 $
45   */
46  public class DefaultOidRegistry implements OidRegistry
47  {
48      /** static class logger */
49      private static final Logger LOG = LoggerFactory.getLogger( DefaultOidRegistry.class );
50  
51      /** Speedup for DEBUG mode */
52      private static final boolean IS_DEBUG = LOG.isDebugEnabled();
53      
54      /** Maps OID to a name or a list of names if more than one name exists */
55      private Map<String, List<String>> byOid = new HashMap<String, List<String>>();
56      
57      /** Maps several names to an OID */
58      private Map<String,String> byName = new HashMap<String,String>();
59  
60  
61      /**
62       * @see org.apache.directory.server.schema.registries.OidRegistry#getOid(java.lang.String)
63       */
64      public String getOid( String name ) throws NamingException
65      {
66          if ( StringTools.isEmpty( name ) )
67          {
68              throw new NamingException( "name should not be empty" );
69          }
70          
71          /* If name is an OID then we return it back since inherently the
72           * OID is another name for the object referred to by OID and the
73           * caller does not know that the argument is an OID String.
74           */
75          if ( StringTools.isDigit( name.charAt( 0 ) ) )
76          {
77              return name;
78          }
79  
80          // If name is mapped to a OID already return OID
81          if ( byName.containsKey( name ) )
82          {
83              String oid = byName.get( name );
84              
85              if ( IS_DEBUG )
86              {
87                  LOG.debug( "looked up OID '" + oid + "' with id '" + name + "'" );
88              }
89              
90              return oid;
91          }
92  
93          /*
94           * As a last resort we check if name is not normalized and if the
95           * normalized version used as a key returns an OID.  If the normalized
96           * name works add the normalized name as a key with its OID to the
97           * byName lookup.  BTW these normalized versions of the key are not
98           * returned on a getNameSet.
99           */
100         String lowerCase = name.trim().toLowerCase();
101         
102         String oid = byName.get( lowerCase );
103         
104         if ( oid != null )
105         {
106             if ( IS_DEBUG )
107             {
108                 LOG.debug( "looked up OID '" + oid + "' with id '" + name + "'" );
109             }
110 
111             return oid;
112         }
113 
114         NamingException fault = new NoSuchAttributeException( "OID for name '" + name + "' was not "
115             + "found within the OID registry" );
116         LOG.error( fault.getMessage() );
117         throw fault;
118     }
119 
120 
121     /**
122      * @see org.apache.directory.server.schema.registries.OidRegistry#hasOid(java.lang.String)
123      */
124     public boolean hasOid( String name )
125     {
126         if ( StringTools.isEmpty( name ) )
127         {
128             return false;
129         }
130         
131         String normalized = name.trim().toLowerCase();
132         
133         return byName.containsKey( normalized );
134     }
135 
136 
137     /**
138      * @see org.apache.directory.server.schema.registries.OidRegistry#getPrimaryName(java.lang.String)
139      */
140     public String getPrimaryName( String oid ) throws NamingException
141     {
142         List<String> value = byOid.get( oid );
143 
144         if ( null == value )
145         {
146             throw new NamingException( "OID '" + oid + "' was not found within the OID registry" );
147         }
148 
149         String name = value.get( 0 );
150         
151         if ( IS_DEBUG )
152         {
153             LOG.debug( "looked up primary name '" + name + "' with OID '" + oid + "'" );
154         }
155         
156         return name;
157     }
158 
159 
160     /**
161      * @see org.apache.directory.server.schema.registries.OidRegistry#getNameSet(java.lang.String)
162      */
163     public List<String> getNameSet( String oid ) throws NamingException
164     {
165         List<String> value = byOid.get( oid );
166 
167         if ( null == value )
168         {
169             throw new NamingException( "OID '" + oid + "' was not found within the OID registry" );
170         }
171 
172         if ( IS_DEBUG )
173         {
174             LOG.debug( "looked up names '" + value + "' for OID '" + oid + "'" );
175         }
176         
177         return value;
178     }
179 
180 
181     /**
182      * @see org.apache.directory.server.schema.registries.OidRegistry#list()
183      */
184     @SuppressWarnings("unchecked")
185     public Iterator list()
186     {
187         return Collections.unmodifiableSet( byOid.keySet() ).iterator();
188     }
189 
190 
191     /**
192      * Get the map of all the oids by their name
193      * @return The Map that contains all the oids
194      */
195     public Map<String, String> getOidByName()
196     {
197         return byName;
198     }
199 
200 
201     /**
202      * Get the map of all the oids by their name
203      * @return The Map that contains all the oids
204      */
205     public Map<String, List<String>> getNameByOid()
206     {
207         return byOid;
208     }
209 
210 
211     /**
212      * @see org.apache.directory.server.schema.registries.OidRegistry#register(String, String)
213      */
214     @SuppressWarnings("unchecked")
215     public void register( String name, String oid ) throws NamingException
216     {
217         if ( !OID.isOID( oid ) )
218         {
219             String message = "Swap the parameter order: the oid " + 
220             "does not start with a digit, or is not an OID!";
221             
222             LOG.debug( message );
223             throw new NamingException( message );
224         }
225         
226         if ( StringTools.isEmpty( name ) )
227         {
228             String message = "The name is empty";
229             LOG.error( message );
230             throw new NamingException( message );
231         }
232 
233         /*
234          * Add the entry for the given name as is and its lowercased version if
235          * the lower cased name is different from the given name name.  
236          */
237         String lowerCase = name.trim().toLowerCase();
238 
239         // Put both the name and the oid as names
240         byName.put( lowerCase, oid );
241         byName.put( oid, oid );
242 
243         /*
244          * Update OID Map
245          * 
246          * 1). Check if we already have a value[s] stored
247          *      1a). Value is a single value and is a String
248          *          Replace value with list containing old and new values
249          *      1b). More than one value stored in a list
250          *          Add new value to the list
251          * 2). If we do not have a value then we just add it as a String
252          */
253         List<String> value;
254         
255         if ( !byOid.containsKey( oid ) )
256         {
257             value = new ArrayList<String>( 1 );
258             value.add( lowerCase );
259         }
260         else
261         {
262             value = byOid.get( oid );
263             
264             if ( value.contains( lowerCase ) )
265             {
266                 return;
267             }
268             else
269             {
270                 value.add( lowerCase );
271             }
272         }
273 
274         byOid.put( oid, value );
275         
276         if ( IS_DEBUG )
277         {
278             LOG.debug( "registed name '" + name + "' with OID: " + oid );
279         }
280     }
281 
282 
283     public void unregister( String numericOid ) throws NamingException
284     {
285         // First, remove the <OID, names> from the byOID map
286         List<String> names = byOid.remove( numericOid );
287         
288         // Then remove all the <name, OID> from the byName map
289         if ( names != null )
290         {
291             for ( String name:names )
292             {
293                 byName.remove( name );
294             }
295         }
296 
297         // Last, remove the <OID, OID> from the byName map
298         byName.remove( numericOid );
299     }
300 }