1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.server.schema.bootstrap;
21
22
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.Comparator;
26 import java.util.HashMap;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Properties;
31 import java.util.Stack;
32
33 import javax.naming.NamingException;
34
35 import org.apache.directory.server.constants.MetaSchemaConstants;
36 import org.apache.directory.server.schema.bootstrap.SystemSchema;
37 import org.apache.directory.server.schema.bootstrap.BootstrapSchema;
38 import org.apache.directory.server.schema.bootstrap.ProducerTypeEnum;
39 import org.apache.directory.server.schema.bootstrap.AbstractBootstrapProducer.BootstrapAttributeType;
40 import org.apache.directory.server.schema.bootstrap.AbstractBootstrapProducer.BootstrapMatchingRule;
41 import org.apache.directory.server.schema.bootstrap.AbstractBootstrapProducer.BootstrapObjectClass;
42 import org.apache.directory.server.schema.bootstrap.AbstractBootstrapProducer.BootstrapSyntax;
43 import org.apache.directory.server.schema.registries.AbstractSchemaLoader;
44 import org.apache.directory.server.schema.registries.AttributeTypeRegistry;
45 import org.apache.directory.server.schema.registries.ComparatorRegistry;
46 import org.apache.directory.server.schema.registries.DefaultRegistries;
47 import org.apache.directory.server.schema.registries.MatchingRuleRegistry;
48 import org.apache.directory.server.schema.registries.NormalizerRegistry;
49 import org.apache.directory.server.schema.registries.ObjectClassRegistry;
50 import org.apache.directory.server.schema.registries.Registries;
51 import org.apache.directory.server.schema.registries.SyntaxCheckerRegistry;
52 import org.apache.directory.server.schema.registries.SyntaxRegistry;
53 import org.apache.directory.shared.ldap.schema.AttributeType;
54 import org.apache.directory.shared.ldap.schema.MatchingRule;
55 import org.apache.directory.shared.ldap.schema.Normalizer;
56 import org.apache.directory.shared.ldap.schema.ObjectClass;
57 import org.apache.directory.shared.ldap.schema.Syntax;
58 import org.apache.directory.shared.ldap.schema.syntax.ComparatorDescription;
59 import org.apache.directory.shared.ldap.schema.syntax.NormalizerDescription;
60 import org.apache.directory.shared.ldap.schema.syntax.SyntaxChecker;
61 import org.apache.directory.shared.ldap.schema.syntax.SyntaxCheckerDescription;
62
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
65
66
67
68
69
70
71
72
73 public class BootstrapSchemaLoader extends AbstractSchemaLoader
74 {
75 private static final Logger log = LoggerFactory.getLogger( BootstrapSchemaLoader.class );
76
77 private ClassLoader cl = getClass().getClassLoader();
78
79
80 private ThreadLocal<BootstrapSchema> schemas;
81
82 private ThreadLocal<Registries> registries;
83
84 private final ProducerCallback cb = new ProducerCallback()
85 {
86 public void schemaObjectProduced( BootstrapProducer producer, String registryKey, Object schemaObject )
87 throws NamingException
88 {
89 register( producer.getType(), registryKey, schemaObject );
90 }
91 };
92
93
94
95
96
97 public BootstrapSchemaLoader()
98 {
99 schemas = new ThreadLocal<BootstrapSchema>();
100 registries = new ThreadLocal<Registries>();
101 }
102
103
104 public BootstrapSchemaLoader( ClassLoader cl )
105 {
106 this();
107 this.cl = cl;
108 }
109
110 public final void loadWithDependencies( Schema schema, Registries registries ) throws Exception
111 {
112 if ( ! ( schema instanceof BootstrapSchema ) )
113 {
114 throw new NamingException( "Expecting schema to be of sub-type BootstrapSchema" );
115 }
116
117 Map<String, Schema> notLoaded = new HashMap<String, Schema>();
118 notLoaded.put( schema.getSchemaName(), schema );
119 Properties props = new Properties();
120 props.put( "package", ( ( BootstrapSchema ) schema ).getPackageName() );
121 loadDepsFirst( schema, new Stack<String>(), notLoaded, schema, registries, props );
122 }
123
124
125
126
127
128
129
130
131
132
133 public final void loadWithDependencies( Collection<Schema> bootstrapSchemas, Registries registries ) throws Exception
134 {
135 BootstrapSchema[] schemas = new BootstrapSchema[bootstrapSchemas.size()];
136 schemas = bootstrapSchemas.toArray( schemas );
137 HashMap<String,Schema> loaded = new HashMap<String,Schema>();
138 HashMap<String,Schema> notLoaded = new HashMap<String,Schema>();
139
140 for ( BootstrapSchema schema:schemas )
141 {
142 notLoaded.put( schema.getSchemaName(), schema );
143 }
144
145 BootstrapSchema schema;
146
147
148
149 schema = new SystemSchema();
150 load( schema, registries, false );
151 notLoaded.remove( schema.getSchemaName() );
152 loaded.put( schema.getSchemaName(), schema );
153
154 Iterator list = notLoaded.values().iterator();
155 while ( list.hasNext() )
156 {
157 schema = ( BootstrapSchema ) list.next();
158 Properties props = new Properties();
159 props.put( "package", schema.getPackageName() );
160 loadDepsFirst( schema, new Stack<String>(), notLoaded, schema, registries, props );
161 list = notLoaded.values().iterator();
162 }
163 }
164
165
166
167
168
169
170
171
172
173 public final void load( Schema schema, Registries registries, boolean isDepLoad ) throws NamingException
174 {
175 if ( registries.getLoadedSchemas().containsKey( schema.getSchemaName() ) )
176 {
177 return;
178 }
179
180 if ( ! ( schema instanceof BootstrapSchema ) )
181 {
182 throw new NamingException( "Expecting schema to be of sub-type BootstrapSchema" );
183 }
184
185 this.registries.set( registries );
186 this.schemas.set( ( BootstrapSchema ) schema );
187
188 for ( ProducerTypeEnum producerType:ProducerTypeEnum.getList() )
189 {
190 BootstrapProducer producer = getProducer( ( BootstrapSchema ) schema, producerType.getName() );
191 producer.produce( registries, cb );
192 }
193
194 notifyListenerOrRegistries( schema, registries );
195 }
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211 private void register( ProducerTypeEnum type, String id, Object schemaObject ) throws NamingException
212 {
213 BootstrapSchema schema = this.schemas.get();
214 DefaultRegistries registries = ( DefaultRegistries ) this.registries.get();
215 List<String> values = new ArrayList<String>(1);
216 values.add( schema.getSchemaName() );
217
218 switch ( type )
219 {
220 case NORMALIZER_PRODUCER :
221 Normalizer normalizer = ( Normalizer ) schemaObject;
222 NormalizerRegistry normalizerRegistry;
223 normalizerRegistry = registries.getNormalizerRegistry();
224
225 NormalizerDescription normalizerDescription = new NormalizerDescription();
226 normalizerDescription.setNumericOid( id );
227 normalizerDescription.setFqcn( normalizer.getClass().getName() );
228 normalizerDescription.addExtension( MetaSchemaConstants.X_SCHEMA, values );
229
230 normalizerRegistry.register( normalizerDescription, normalizer );
231 break;
232
233 case COMPARATOR_PRODUCER :
234 Comparator comparator = ( Comparator ) schemaObject;
235 ComparatorRegistry comparatorRegistry;
236 comparatorRegistry = registries.getComparatorRegistry();
237
238 ComparatorDescription comparatorDescription = new ComparatorDescription();
239 comparatorDescription.addExtension( MetaSchemaConstants.X_SCHEMA, values );
240 comparatorDescription.setFqcn( comparator.getClass().getName() );
241 comparatorDescription.setNumericOid( id );
242
243 comparatorRegistry.register( comparatorDescription, comparator );
244 break;
245
246 case SYNTAX_CHECKER_PRODUCER :
247 SyntaxChecker syntaxChecker = ( SyntaxChecker ) schemaObject;
248 SyntaxCheckerRegistry syntaxCheckerRegistry;
249 syntaxCheckerRegistry = registries.getSyntaxCheckerRegistry();
250
251 SyntaxCheckerDescription syntaxCheckerDescription = new SyntaxCheckerDescription();
252 syntaxCheckerDescription.addExtension( MetaSchemaConstants.X_SCHEMA, values );
253 syntaxCheckerDescription.setFqcn( syntaxChecker.getClass().getName() );
254 syntaxCheckerDescription.setNumericOid( id );
255
256 syntaxCheckerRegistry.register( syntaxCheckerDescription, syntaxChecker );
257 break;
258
259 case SYNTAX_PRODUCER :
260 Syntax syntax = ( Syntax ) schemaObject;
261
262 if ( schemaObject instanceof BootstrapSyntax )
263 {
264 ( ( BootstrapSyntax ) syntax ).setSchema( schema.getSchemaName() );
265 }
266
267 SyntaxRegistry syntaxRegistry = registries.getSyntaxRegistry();
268 syntaxRegistry.register( syntax );
269 break;
270
271 case MATCHING_RULE_PRODUCER :
272 MatchingRule matchingRule = ( MatchingRule ) schemaObject;
273
274 if ( schemaObject instanceof BootstrapMatchingRule )
275 {
276 ( ( BootstrapMatchingRule ) matchingRule ).setSchema( schema.getSchemaName() );
277 }
278
279 MatchingRuleRegistry matchingRuleRegistry;
280 matchingRuleRegistry = registries.getMatchingRuleRegistry();
281 matchingRuleRegistry.register( matchingRule );
282 break;
283
284 case ATTRIBUTE_TYPE_PRODUCER :
285 AttributeType attributeType = ( AttributeType ) schemaObject;
286
287 if ( attributeType instanceof BootstrapAttributeType )
288 {
289 ( ( BootstrapAttributeType ) attributeType ).setSchema( schema.getSchemaName() );
290 }
291
292 AttributeTypeRegistry attributeTypeRegistry;
293 attributeTypeRegistry = registries.getAttributeTypeRegistry();
294 attributeTypeRegistry.register( attributeType );
295 break;
296
297 case OBJECT_CLASS_PRODUCER :
298 ObjectClass objectClass = ( ObjectClass ) schemaObject;
299
300 if ( objectClass instanceof BootstrapObjectClass )
301 {
302 ( ( BootstrapObjectClass ) objectClass ).setSchema( schema.getSchemaName() );
303 }
304
305 ObjectClassRegistry objectClassRegistry;
306 objectClassRegistry = registries.getObjectClassRegistry();
307 objectClassRegistry.register( objectClass );
308 break;
309
310 default:
311 throw new IllegalStateException( "ProducerTypeEnum value is invalid: " + type );
312 }
313 }
314
315
316
317
318
319
320
321
322
323
324 private BootstrapProducer getProducer( BootstrapSchema schema, String producerBase ) throws NamingException
325 {
326 Class<?> clazz = null;
327 boolean failedTargetLoad = false;
328 String defaultClassName;
329 String targetClassName = schema.getBaseClassName() + producerBase;
330
331 try
332 {
333 clazz = Class.forName( targetClassName, true, cl );
334 }
335 catch ( ClassNotFoundException e )
336 {
337 failedTargetLoad = true;
338 log.debug( "Failed to load '" + targetClassName + "'. Trying the alternative.", e );
339 }
340
341 if ( failedTargetLoad )
342 {
343 defaultClassName = schema.getDefaultBaseClassName() + producerBase;
344
345 try
346 {
347 clazz = Class.forName( defaultClassName, true, cl );
348 }
349 catch ( ClassNotFoundException e )
350 {
351 NamingException ne = new NamingException( "Failed to load " + producerBase + " for "
352 + schema.getSchemaName() + " schema using following classes: " + targetClassName + ", "
353 + defaultClassName );
354 ne.setRootCause( e );
355 throw ne;
356 }
357 }
358
359 try
360 {
361 return ( BootstrapProducer ) clazz.newInstance();
362 }
363 catch ( IllegalAccessException e )
364 {
365 NamingException ne = new NamingException( "Failed to create " + clazz );
366 ne.setRootCause( e );
367 throw ne;
368 }
369 catch ( InstantiationException e )
370 {
371 NamingException ne = new NamingException( "Failed to create " + clazz );
372 ne.setRootCause( e );
373 throw ne;
374 }
375 }
376
377
378 public Schema getSchema( String schemaName ) throws NamingException
379 {
380 return getSchema( schemaName, null );
381 }
382
383
384 public Schema getSchema( String schemaName, Properties schemaProperties ) throws NamingException
385 {
386 String baseName = schemaName;
387 schemaName = schemaName.toLowerCase();
388 StringBuffer buf = new StringBuffer();
389
390
391 if ( schemaProperties == null || schemaProperties.getProperty( "package" ) == null )
392 {
393
394 Properties props = new Properties();
395 props.put( "package", "org.apache.directory.server.schema.bootstrap" );
396
397 try
398 {
399 Schema schema = getSchema( baseName, props );
400 return schema;
401 }
402 catch( NamingException e )
403 {
404 throw new NamingException( "Can't find the bootstrap schema class in the default " +
405 "\n bootstrap schema package. I need a package name property with key \"package\"." );
406 }
407 }
408
409 buf.append( schemaProperties.getProperty( "package" ) );
410 buf.append( '.' );
411 buf.append( Character.toUpperCase( schemaName.charAt( 0 ) ) );
412 buf.append( schemaName.substring( 1 ) );
413 schemaName = buf.toString();
414
415 Schema schema = null;
416 try
417 {
418 schema = ( Schema ) Class.forName( schemaName, true, cl ).newInstance();
419 }
420 catch ( InstantiationException e )
421 {
422 NamingException ne = new NamingException( "Failed to instantiate schema object: " + schemaName );
423 ne.setRootCause( e );
424 throw ne;
425 }
426 catch ( IllegalAccessException e )
427 {
428 NamingException ne =
429 new NamingException( "Failed to access default constructor of schema object: " + schemaName );
430 ne.setRootCause( e );
431 throw ne;
432 }
433 catch ( ClassNotFoundException e )
434 {
435 NamingException ne = new NamingException( "Schema class not found: " + schemaName );
436 ne.setRootCause( e );
437 throw ne;
438 }
439
440 return schema;
441 }
442 }