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