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