1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.ldap.server.schema.bootstrap;
18
19
20 import java.util.Collection;
21 import java.util.Comparator;
22 import java.util.HashMap;
23 import java.util.Iterator;
24 import java.util.List;
25 import java.util.Stack;
26
27 import javax.naming.NamingException;
28
29 import org.apache.ldap.common.schema.AttributeType;
30 import org.apache.ldap.common.schema.DITContentRule;
31 import org.apache.ldap.common.schema.DITStructureRule;
32 import org.apache.ldap.common.schema.MatchingRule;
33 import org.apache.ldap.common.schema.MatchingRuleUse;
34 import org.apache.ldap.common.schema.NameForm;
35 import org.apache.ldap.common.schema.Normalizer;
36 import org.apache.ldap.common.schema.ObjectClass;
37 import org.apache.ldap.common.schema.Syntax;
38 import org.apache.ldap.common.schema.SyntaxChecker;
39 import org.apache.ldap.server.jndi.ServerDirObjectFactory;
40 import org.apache.ldap.server.jndi.ServerDirStateFactory;
41 import org.apache.ldap.server.schema.AttributeTypeRegistry;
42 import org.apache.ldap.server.schema.ComparatorRegistry;
43 import org.apache.ldap.server.schema.DITContentRuleRegistry;
44 import org.apache.ldap.server.schema.DITStructureRuleRegistry;
45 import org.apache.ldap.server.schema.MatchingRuleRegistry;
46 import org.apache.ldap.server.schema.MatchingRuleUseRegistry;
47 import org.apache.ldap.server.schema.NameFormRegistry;
48 import org.apache.ldap.server.schema.NormalizerRegistry;
49 import org.apache.ldap.server.schema.ObjectClassRegistry;
50 import org.apache.ldap.server.schema.ObjectFactoryRegistry;
51 import org.apache.ldap.server.schema.StateFactoryRegistry;
52 import org.apache.ldap.server.schema.SyntaxCheckerRegistry;
53 import org.apache.ldap.server.schema.SyntaxRegistry;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56
57
58 /***
59 * Class which handles bootstrap schema class file loading.
60 *
61 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
62 * @version $Rev: 280870 $
63 */
64 public class BootstrapSchemaLoader
65 {
66 private static final Logger log = LoggerFactory.getLogger( BootstrapSchemaLoader.class );
67
68 /*** stores schemas of producers for callback access */
69 private ThreadLocal schemas;
70 /*** stores registries associated with producers for callback access */
71 private ThreadLocal registries;
72 /*** the callback that just calls register() */
73 private final ProducerCallback cb = new ProducerCallback()
74 {
75 public void schemaObjectProduced( BootstrapProducer producer,
76 String registryKey,
77 Object schemaObject )
78 throws NamingException
79 {
80 register( producer.getType(), registryKey, schemaObject );
81 }
82 };
83
84
85 /***
86 * Creates a BootstrapSchema loader.
87 */
88 public BootstrapSchemaLoader()
89 {
90 schemas = new ThreadLocal();
91 registries = new ThreadLocal();
92 }
93
94
95
96 /***
97 * Loads a set of schemas by loading and running all producers for each
98 * dependent schema first.
99 *
100 * @param bootstrapSchemas Collection of {@link BootstrapSchema}s to load
101 * @param registries the registries to fill with producer created objects
102 * @throws NamingException if there are any failures during this process
103 */
104 public final void load( Collection bootstrapSchemas, BootstrapRegistries registries )
105 throws NamingException
106 {
107 BootstrapSchema[] schemas = new BootstrapSchema[ bootstrapSchemas.size() ];
108 schemas = ( BootstrapSchema[] ) bootstrapSchemas.toArray( schemas );
109 HashMap loaded = new HashMap();
110 HashMap notLoaded = new HashMap();
111
112 for ( int ii = 0; ii < schemas.length; ii++ )
113 {
114 notLoaded.put( schemas[ii].getSchemaName(), schemas[ii] );
115 }
116
117 BootstrapSchema schema;
118
119
120
121 schema = new SystemSchema();
122 load( schema, registries );
123 notLoaded.remove( schema.getSchemaName() );
124 loaded.put( schema.getSchemaName(), schema );
125
126 Iterator list = notLoaded.values().iterator();
127 while ( list.hasNext() )
128 {
129 schema = ( BootstrapSchema ) list.next();
130 loadDepsFirst( new Stack(), notLoaded, schema, registries );
131 list = notLoaded.values().iterator();
132 }
133 }
134
135
136 /***
137 * Recursive method which loads schema's with their dependent schemas first
138 * and tracks what schemas it has seen so the recursion does not go out of
139 * control with depenency cycle detection.
140 *
141 * @param beenthere stack of schema names we have visited and have yet to load
142 * @param notLoaded hash of schemas keyed by name which have yet to be loaded
143 * @param schema the current schema we are attempting to load
144 * @param registries the set of registries to use while loading
145 * @throws NamingException if there is a cycle detected and/or another
146 * failure results while loading, producing and or registering schema objects
147 */
148 public final void loadDepsFirst( Stack beenthere, HashMap notLoaded,
149 BootstrapSchema schema,
150 BootstrapRegistries registries )
151 throws NamingException
152 {
153 beenthere.push( schema.getSchemaName() );
154 String[] deps = schema.getDependencies();
155
156
157 if ( deps == null || deps.length == 0 )
158 {
159 load( schema, registries );
160 notLoaded.remove( schema.getSchemaName() );
161 beenthere.pop();
162 return;
163 }
164
165
166
167
168
169
170 for ( int ii = 0; ii < deps.length; ii++ )
171 {
172 if ( ! notLoaded.containsKey( deps[ii] ) )
173 {
174 continue;
175 }
176
177 BootstrapSchema dep = ( BootstrapSchema ) notLoaded.get( deps[ii] );
178
179 if ( beenthere.contains( dep.getSchemaName() ) )
180 {
181
182 beenthere.push( dep.getSchemaName() );
183 throw new NamingException( "schema dependency cycle detected: "
184 + beenthere );
185 }
186
187 loadDepsFirst( beenthere, notLoaded, dep, registries );
188 }
189
190
191 load( schema, registries );
192 notLoaded.remove( schema.getSchemaName() );
193 beenthere.pop();
194 }
195
196
197 /***
198 * Loads a schema by loading and running all producers for te schema.
199 *
200 * @param schema the schema to load
201 * @param registries the registries to fill with producer created objects
202 * @throws NamingException if there are any failures during this process
203 */
204 public final void load( BootstrapSchema schema, BootstrapRegistries registries )
205 throws NamingException
206 {
207 this.registries.set( registries );
208 this.schemas.set( schema );
209
210 List producers = ProducerTypeEnum.list();
211 for ( int ii = 0; ii < producers.size(); ii++ )
212 {
213 ProducerTypeEnum producerType = ( ProducerTypeEnum ) producers.get( ii );
214 BootstrapProducer producer = getProducer( schema, producerType.getName() );
215 producer.produce( registries, cb );
216 }
217 }
218
219
220
221
222
223
224
225 /***
226 * Registers objects
227 *
228 * @param type the type of the producer which determines the type of object produced
229 * @param id the primary key identifying the created object in a registry
230 * @param schemaObject the object being registered
231 * @throws NamingException if there are problems when registering the object
232 * in any of the registries
233 */
234 private void register( ProducerTypeEnum type, String id,
235 Object schemaObject ) throws NamingException
236 {
237 BootstrapSchema schema = ( BootstrapSchema ) this.schemas.get();
238 BootstrapRegistries registries = ( BootstrapRegistries ) this.registries.get();
239
240 switch( type.getValue() )
241 {
242 case( ProducerTypeEnum.NORMALIZER_PRODUCER_VAL ):
243 Normalizer normalizer = ( Normalizer ) schemaObject;
244 NormalizerRegistry normalizerRegistry;
245 normalizerRegistry = registries.getNormalizerRegistry();
246 normalizerRegistry.register( schema.getSchemaName(), id, normalizer );
247 break;
248 case( ProducerTypeEnum.COMPARATOR_PRODUCER_VAL ):
249 Comparator comparator = ( Comparator ) schemaObject;
250 ComparatorRegistry comparatorRegistry;
251 comparatorRegistry = registries.getComparatorRegistry();
252 comparatorRegistry.register( schema.getSchemaName(), id, comparator );
253 break;
254 case( ProducerTypeEnum.SYNTAX_CHECKER_PRODUCER_VAL ):
255 SyntaxChecker syntaxChecker = ( SyntaxChecker ) schemaObject;
256 SyntaxCheckerRegistry syntaxCheckerRegistry;
257 syntaxCheckerRegistry = registries.getSyntaxCheckerRegistry();
258 syntaxCheckerRegistry.register( schema.getSchemaName(), id, syntaxChecker );
259 break;
260 case( ProducerTypeEnum.SYNTAX_PRODUCER_VAL ):
261 Syntax syntax = ( Syntax ) schemaObject;
262 SyntaxRegistry syntaxRegistry = registries.getSyntaxRegistry();
263 syntaxRegistry.register( schema.getSchemaName(), syntax );
264 break;
265 case( ProducerTypeEnum.MATCHING_RULE_PRODUCER_VAL ):
266 MatchingRule matchingRule = ( MatchingRule ) schemaObject;
267 MatchingRuleRegistry matchingRuleRegistry;
268 matchingRuleRegistry = registries.getMatchingRuleRegistry();
269 matchingRuleRegistry.register( schema.getSchemaName(), matchingRule );
270 break;
271 case( ProducerTypeEnum.ATTRIBUTE_TYPE_PRODUCER_VAL ):
272 AttributeType attributeType = ( AttributeType ) schemaObject;
273 AttributeTypeRegistry attributeTypeRegistry;
274 attributeTypeRegistry = registries.getAttributeTypeRegistry();
275 attributeTypeRegistry.register( schema.getSchemaName(), attributeType );
276 break;
277 case( ProducerTypeEnum.OBJECT_CLASS_PRODUCER_VAL ):
278 ObjectClass objectClass = ( ObjectClass ) schemaObject;
279 ObjectClassRegistry objectClassRegistry;
280 objectClassRegistry = registries.getObjectClassRegistry();
281 objectClassRegistry.register( schema.getSchemaName(), objectClass );
282 break;
283 case( ProducerTypeEnum.MATCHING_RULE_USE_PRODUCER_VAL ):
284 MatchingRuleUse matchingRuleUse = ( MatchingRuleUse ) schemaObject;
285 MatchingRuleUseRegistry matchingRuleUseRegistry;
286 matchingRuleUseRegistry = registries.getMatchingRuleUseRegistry();
287 matchingRuleUseRegistry.register( schema.getSchemaName(), matchingRuleUse );
288 break;
289 case( ProducerTypeEnum.DIT_CONTENT_RULE_PRODUCER_VAL ):
290 DITContentRule ditContentRule = ( DITContentRule ) schemaObject;
291 DITContentRuleRegistry ditContentRuleRegistry;
292 ditContentRuleRegistry = registries.getDitContentRuleRegistry();
293 ditContentRuleRegistry.register( schema.getSchemaName(), ditContentRule );
294 break;
295 case( ProducerTypeEnum.NAME_FORM_PRODUCER_VAL ):
296 NameForm nameForm = ( NameForm ) schemaObject;
297 NameFormRegistry nameFormRegistry;
298 nameFormRegistry = registries.getNameFormRegistry();
299 nameFormRegistry.register( schema.getSchemaName(), nameForm );
300 break;
301 case( ProducerTypeEnum.DIT_STRUCTURE_RULE_PRODUCER_VAL ):
302 DITStructureRule ditStructureRule = ( DITStructureRule ) schemaObject;
303 DITStructureRuleRegistry ditStructureRuleRegistry;
304 ditStructureRuleRegistry = registries.getDitStructureRuleRegistry();
305 ditStructureRuleRegistry.register( schema.getSchemaName(), ditStructureRule );
306 break;
307 case( ProducerTypeEnum.STATE_FACTORY_PRODUCER_VAL ):
308 ServerDirStateFactory stateFactory = ( ServerDirStateFactory ) schemaObject;
309 StateFactoryRegistry stateFactoryRegistry;
310 stateFactoryRegistry = registries.getStateFactoryRegistry();
311 stateFactoryRegistry.register( stateFactory );
312 break;
313 case( ProducerTypeEnum.OBJECT_FACTORY_PRODUCER_VAL ):
314 ServerDirObjectFactory objectFactory = ( ServerDirObjectFactory ) schemaObject;
315 ObjectFactoryRegistry objectFactoryRegistry;
316 objectFactoryRegistry = registries.getObjectFactoryRegistry();
317 objectFactoryRegistry.register( objectFactory );
318 break;
319 default:
320 throw new IllegalStateException( "ProducerTypeEnum is broke!" );
321 }
322 }
323
324
325 /***
326 * Attempts first to try to load the target class for the Producer,
327 * then tries for the default if the target load fails.
328 *
329 * @param schema the bootstrap schema
330 * @param producerBase the producer's base name
331 * @throws NamingException if there are failures loading classes
332 */
333 private BootstrapProducer getProducer( BootstrapSchema schema, String producerBase )
334 throws NamingException
335 {
336 Class clazz = null;
337 boolean failedTargetLoad = false;
338 String defaultClassName;
339 String targetClassName = schema.getBaseClassName() + producerBase;
340
341 try
342 {
343 clazz = Class.forName( targetClassName );
344 }
345 catch ( ClassNotFoundException e )
346 {
347 failedTargetLoad = true;
348 log.debug( "Failed to load '" + targetClassName + "'. Trying the alternative.", e );
349 }
350
351 if ( failedTargetLoad )
352 {
353 defaultClassName = schema.getDefaultBaseClassName() + producerBase;
354
355 try
356 {
357 clazz = Class.forName( defaultClassName );
358 }
359 catch ( ClassNotFoundException e )
360 {
361 NamingException ne = new NamingException( "Failed to load " +
362 producerBase + " for " + schema.getSchemaName()
363 + " schema using following classes: " + targetClassName
364 + ", " + defaultClassName );
365 ne.setRootCause( e );
366 throw ne;
367 }
368 }
369
370 try
371 {
372 return ( BootstrapProducer ) clazz.newInstance();
373 }
374 catch ( IllegalAccessException e )
375 {
376 NamingException ne = new NamingException( "Failed to create " + clazz );
377 ne.setRootCause( e );
378 throw ne;
379 }
380 catch ( InstantiationException e )
381 {
382 NamingException ne = new NamingException( "Failed to create " + clazz );
383 ne.setRootCause( e );
384 throw ne;
385 }
386 }
387 }