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 }