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.core.schema;
21
22 import java.lang.reflect.InvocationTargetException;
23 import java.lang.reflect.Method;
24 import java.util.ArrayList;
25 import java.util.Comparator;
26 import java.util.HashSet;
27 import java.util.List;
28 import java.util.Set;
29
30 import javax.naming.NamingException;
31
32 import org.apache.directory.server.constants.MetaSchemaConstants;
33 import org.apache.directory.server.core.entry.DefaultServerAttribute;
34 import org.apache.directory.server.core.entry.ServerAttribute;
35 import org.apache.directory.server.core.entry.ServerEntry;
36 import org.apache.directory.server.schema.bootstrap.Schema;
37 import org.apache.directory.server.schema.registries.Registries;
38 import org.apache.directory.shared.ldap.constants.SchemaConstants;
39 import org.apache.directory.shared.ldap.entry.EntryAttribute;
40 import org.apache.directory.shared.ldap.entry.Value;
41 import org.apache.directory.shared.ldap.exception.LdapNamingException;
42 import org.apache.directory.shared.ldap.message.ResultCodeEnum;
43 import org.apache.directory.shared.ldap.schema.AttributeType;
44 import org.apache.directory.shared.ldap.schema.MatchingRule;
45 import org.apache.directory.shared.ldap.schema.MutableSchemaObject;
46 import org.apache.directory.shared.ldap.schema.Normalizer;
47 import org.apache.directory.shared.ldap.schema.ObjectClass;
48 import org.apache.directory.shared.ldap.schema.ObjectClassTypeEnum;
49 import org.apache.directory.shared.ldap.schema.Syntax;
50 import org.apache.directory.shared.ldap.schema.UsageEnum;
51 import org.apache.directory.shared.ldap.schema.syntax.ComparatorDescription;
52 import org.apache.directory.shared.ldap.schema.syntax.NormalizerDescription;
53 import org.apache.directory.shared.ldap.schema.syntax.SyntaxChecker;
54 import org.apache.directory.shared.ldap.schema.syntax.SyntaxCheckerDescription;
55 import org.apache.directory.shared.ldap.util.Base64;
56
57
58
59
60
61
62
63
64 public class SchemaEntityFactory
65 {
66
67 private final static Class<?>[] parameterTypes = new Class[] { Registries.class };
68
69
70 private final static Class<?>[] setOidParameterTypes = new Class[] { String.class };
71
72 private static final String[] EMPTY = new String[0];
73
74
75 private final Registries bootstrapRegistries;
76
77 private final AttributeClassLoader classLoader;
78 private final AttributeType oidAT;
79 private final AttributeType byteCodeAT;
80
81
82 public SchemaEntityFactory( Registries bootstrapRegistries ) throws NamingException
83 {
84 this.bootstrapRegistries = bootstrapRegistries;
85 this.classLoader = new AttributeClassLoader();
86 this.oidAT = bootstrapRegistries.getAttributeTypeRegistry().lookup( MetaSchemaConstants.M_OID_AT );
87 this.byteCodeAT = bootstrapRegistries.getAttributeTypeRegistry().lookup( MetaSchemaConstants.M_BYTECODE_AT );
88 }
89
90
91 public Schema getSchema( ServerEntry entry ) throws NamingException
92 {
93 String name;
94 String owner;
95 String[] dependencies = EMPTY;
96 boolean isDisabled = false;
97
98 if ( entry == null )
99 {
100 throw new NullPointerException( "entry cannot be null" );
101 }
102
103 if ( entry.get( SchemaConstants.CN_AT ) == null )
104 {
105 throw new NullPointerException( "entry must have a valid cn attribute" );
106 }
107
108 name = entry.get( SchemaConstants.CN_AT ).getString();
109
110 if ( entry.get( SchemaConstants.CREATORS_NAME_AT ) == null )
111 {
112 throw new NullPointerException( "entry must have a valid "
113 + SchemaConstants.CREATORS_NAME_AT + " attribute" );
114 }
115
116 owner = entry.get( SchemaConstants.CREATORS_NAME_AT ).getString();
117
118 if ( entry.get( MetaSchemaConstants.M_DISABLED_AT ) != null )
119 {
120 String value = entry.get( MetaSchemaConstants.M_DISABLED_AT ).getString();
121 value = value.toUpperCase();
122 isDisabled = value.equals( "TRUE" );
123 }
124
125 if ( entry.get( MetaSchemaConstants.M_DEPENDENCIES_AT ) != null )
126 {
127 Set<String> depsSet = new HashSet<String>();
128 EntryAttribute depsAttr = entry.get( MetaSchemaConstants.M_DEPENDENCIES_AT );
129
130 for ( Value<?> value:depsAttr )
131 {
132 depsSet.add( (String)value.get() );
133 }
134
135 dependencies = depsSet.toArray( EMPTY );
136 }
137
138 return new AbstractSchema( name, owner, dependencies, isDisabled ){};
139 }
140
141
142 private SyntaxChecker getSyntaxChecker( String syntaxOid, String className, EntryAttribute bytecode, Registries targetRegistries )
143 throws NamingException
144 {
145 Class<?> clazz = null;
146 SyntaxChecker syntaxChecker = null;
147
148 try
149 {
150 if ( bytecode == null )
151 {
152 clazz = Class.forName( className );
153 }
154 else
155 {
156 classLoader.setAttribute( bytecode );
157 clazz = classLoader.loadClass( className );
158 }
159 }
160 catch ( ClassNotFoundException e )
161 {
162 LdapNamingException ne = new LdapNamingException(
163 "Normalizer class "+ className + " was not found", ResultCodeEnum.OTHER );
164 ne.setRootCause( e );
165 throw ne;
166 }
167
168 try
169 {
170 syntaxChecker = ( SyntaxChecker ) clazz.newInstance();
171 }
172 catch ( InstantiationException e )
173 {
174 LdapNamingException ne = new LdapNamingException( "Failed to instantiate SyntaxChecker class "+ className
175 + ".\nCheck that a default constructor exists for the class.", ResultCodeEnum.OTHER );
176 ne.setRootCause( e );
177 throw ne;
178 }
179 catch ( IllegalAccessException e )
180 {
181 LdapNamingException ne = new LdapNamingException( "Failed to instantiate SyntaxChecker class "+ className
182 + ".\nCheck that a **PUBLIC** accessible default constructor exists for the class.",
183 ResultCodeEnum.OTHER );
184 ne.setRootCause( e );
185 throw ne;
186 }
187
188
189 injectRegistries( syntaxChecker, targetRegistries );
190 injectOid( syntaxOid, syntaxChecker );
191 return syntaxChecker;
192 }
193
194
195
196
197
198
199
200
201
202 public SyntaxChecker getSyntaxChecker( ServerEntry entry, Registries targetRegistries ) throws NamingException
203 {
204 if ( entry == null )
205 {
206 throw new NullPointerException( "entry cannot be null" );
207 }
208
209 if ( entry.get( MetaSchemaConstants.M_FQCN_AT ) == null )
210 {
211 throw new NullPointerException( "entry must have a valid "
212 + MetaSchemaConstants.M_FQCN_AT + " attribute" );
213 }
214
215 String className = ( String ) entry.get( MetaSchemaConstants.M_FQCN_AT ).get().get();
216 String syntaxOid = ( String ) entry.get( oidAT ).get().get();
217 return getSyntaxChecker( syntaxOid, className, entry.get( byteCodeAT ),
218 targetRegistries );
219 }
220
221
222 public SyntaxChecker getSyntaxChecker( SyntaxCheckerDescription syntaxCheckerDescription,
223 Registries targetRegistries ) throws NamingException
224 {
225 ServerAttribute attr = null;
226
227 if ( syntaxCheckerDescription.getBytecode() != null )
228 {
229 byte[] bytecode = Base64.decode( syntaxCheckerDescription.getBytecode().toCharArray() );
230 AttributeType byteCodeAT = targetRegistries.getAttributeTypeRegistry().lookup( MetaSchemaConstants.M_BYTECODE_AT );
231 attr = new DefaultServerAttribute( byteCodeAT, bytecode );
232 }
233
234 return getSyntaxChecker( syntaxCheckerDescription.getNumericOid(),
235 syntaxCheckerDescription.getFqcn(), attr, targetRegistries );
236 }
237
238
239 private Comparator getComparator( String className, EntryAttribute bytecode, Registries targetRegistries )
240 throws NamingException
241 {
242 Comparator comparator = null;
243 Class<?> clazz = null;
244
245 if ( bytecode == null )
246 {
247 try
248 {
249 clazz = Class.forName( className );
250 }
251 catch ( ClassNotFoundException e )
252 {
253 LdapNamingException ne = new LdapNamingException( "Comparator class "+ className + " was not found",
254 ResultCodeEnum.OTHER );
255 ne.setRootCause( e );
256 throw ne;
257 }
258 }
259 else
260 {
261 classLoader.setAttribute( bytecode );
262
263 try
264 {
265 clazz = classLoader.loadClass( className );
266 }
267 catch ( ClassNotFoundException e )
268 {
269 LdapNamingException ne = new LdapNamingException( "Comparator class "+ className + " was not found",
270 ResultCodeEnum.OTHER );
271 ne.setRootCause( e );
272 throw ne;
273 }
274 }
275
276 try
277 {
278 comparator = ( Comparator ) clazz.newInstance();
279 }
280 catch ( InstantiationException e )
281 {
282 NamingException ne = new NamingException( "Failed to instantiate comparator class "+ className
283 + ".\nCheck that a default constructor exists for the class." );
284 ne.setRootCause( e );
285 throw ne;
286 }
287 catch ( IllegalAccessException e )
288 {
289 NamingException ne = new NamingException( "Failed to instantiate comparator class "+ className
290 + ".\nCheck that a **PUBLIC** accessible default constructor exists for the class." );
291 ne.setRootCause( e );
292 throw ne;
293 }
294
295 injectRegistries( comparator, targetRegistries );
296 return comparator;
297 }
298
299
300 public Comparator getComparator( ComparatorDescription comparatorDescription, Registries targetRegistries )
301 throws NamingException
302 {
303 ServerAttribute attr = null;
304
305 if ( comparatorDescription.getBytecode() != null )
306 {
307 byte[] bytecode = Base64.decode( comparatorDescription.getBytecode().toCharArray() );
308 AttributeType byteCodeAT = targetRegistries.getAttributeTypeRegistry().lookup( MetaSchemaConstants.M_BYTECODE_AT );
309 attr = new DefaultServerAttribute( byteCodeAT, bytecode );
310 }
311
312 return getComparator( comparatorDescription.getFqcn(), attr, targetRegistries );
313 }
314
315
316
317
318
319
320
321
322
323 public Comparator getComparator( ServerEntry entry, Registries targetRegistries ) throws NamingException
324 {
325 if ( entry == null )
326 {
327 throw new NullPointerException( "entry cannot be null" );
328 }
329
330 if ( entry.get( MetaSchemaConstants.M_FQCN_AT ) == null )
331 {
332 throw new NullPointerException( "entry must have a valid "
333 + MetaSchemaConstants.M_FQCN_AT + " attribute" );
334 }
335
336 String className = ( String ) entry.get( MetaSchemaConstants.M_FQCN_AT ).get().get();
337 return getComparator( className, entry.get( MetaSchemaConstants.M_BYTECODE_AT ), targetRegistries );
338 }
339
340
341 private Normalizer getNormalizer( String className, EntryAttribute bytecode, Registries targetRegistries )
342 throws NamingException
343 {
344 Class<?> clazz = null;
345 Normalizer normalizer = null;
346
347 try
348 {
349 if ( bytecode == null )
350 {
351 clazz = Class.forName( className );
352 }
353 else
354 {
355 classLoader.setAttribute( bytecode );
356 clazz = classLoader.loadClass( className );
357 }
358 }
359 catch ( ClassNotFoundException e )
360 {
361 LdapNamingException ne = new LdapNamingException(
362 "Normalizer class "+ className + " was not found", ResultCodeEnum.OTHER );
363 ne.setRootCause( e );
364 throw ne;
365 }
366
367 try
368 {
369 normalizer = ( Normalizer ) clazz.newInstance();
370 }
371 catch ( InstantiationException e )
372 {
373 LdapNamingException ne = new LdapNamingException( "Failed to instantiate normalizer class "+ className
374 + ".\nCheck that a default constructor exists for the class.", ResultCodeEnum.OTHER );
375 ne.setRootCause( e );
376 throw ne;
377 }
378 catch ( IllegalAccessException e )
379 {
380 LdapNamingException ne = new LdapNamingException( "Failed to instantiate normalizer class "+ className
381 + ".\nCheck that a **PUBLIC** accessible default constructor exists for the class.",
382 ResultCodeEnum.OTHER );
383 ne.setRootCause( e );
384 throw ne;
385 }
386
387
388 injectRegistries( normalizer, targetRegistries );
389 return normalizer;
390 }
391
392
393 public Normalizer getNormalizer( NormalizerDescription normalizerDescription, Registries targetRegistries )
394 throws NamingException
395 {
396 ServerAttribute attr = null;
397
398 if ( normalizerDescription.getBytecode() != null )
399 {
400 byte[] bytecode = Base64.decode( normalizerDescription.getBytecode().toCharArray() );
401 AttributeType byteCodeAT = targetRegistries.getAttributeTypeRegistry().lookup( MetaSchemaConstants.M_BYTECODE_AT );
402 attr = new DefaultServerAttribute( byteCodeAT, bytecode );
403 }
404
405 return getNormalizer( normalizerDescription.getFqcn(), attr, targetRegistries );
406 }
407
408
409
410
411
412
413
414
415
416 public Normalizer getNormalizer( ServerEntry entry, Registries targetRegistries ) throws NamingException
417 {
418 if ( entry == null )
419 {
420 throw new NullPointerException( "entry cannot be null" );
421 }
422
423 if ( entry.get( MetaSchemaConstants.M_FQCN_AT ) == null )
424 {
425 throw new NullPointerException( "entry must have a valid "
426 + MetaSchemaConstants.M_FQCN_AT + " attribute" );
427 }
428
429 String className = ( String ) entry.get( MetaSchemaConstants.M_FQCN_AT ).get().get();
430 return getNormalizer( className, entry.get( MetaSchemaConstants.M_BYTECODE_AT ), targetRegistries );
431 }
432
433
434
435
436
437
438
439
440
441 private void injectRegistries( Object obj, Registries targetRegistries ) throws NamingException
442 {
443 String className = obj.getClass().getName();
444
445 try
446 {
447 Method method = obj.getClass().getMethod( "setRegistries", parameterTypes );
448
449 if ( method == null )
450 {
451 return;
452 }
453
454 Object[] args = new Object[] { this.bootstrapRegistries };
455 method.invoke( obj, args );
456 }
457 catch ( SecurityException e )
458 {
459 NamingException ne = new NamingException( "SyntaxChecker class "+ className
460 + " could not have the Registries dependency injected." );
461 ne.setRootCause( e );
462 throw ne;
463 }
464 catch ( NoSuchMethodException e )
465 {
466
467 }
468 catch ( IllegalArgumentException e )
469 {
470 NamingException ne = new NamingException( "SyntaxChecker class "+ className
471 + " could not have the Registries dependency injected." );
472 ne.setRootCause( e );
473 throw ne;
474 }
475 catch ( IllegalAccessException e )
476 {
477 NamingException ne = new NamingException( "SyntaxChecker class "+ className
478 + " could not have the Registries dependency injected." );
479 ne.setRootCause( e );
480 throw ne;
481 }
482 catch ( InvocationTargetException e )
483 {
484 NamingException ne = new NamingException( "SyntaxChecker class "+ className
485 + " could not have the Registries dependency injected." );
486 ne.setRootCause( e );
487 throw ne;
488 }
489 }
490
491
492
493
494
495
496
497
498
499 private void injectOid( String syntaxOid, SyntaxChecker checker ) throws NamingException
500 {
501 String className = checker.getClass().getName();
502
503 try
504 {
505 Method method = checker.getClass().getMethod( "setSyntaxOid", setOidParameterTypes );
506
507 if ( method == null )
508 {
509 return;
510 }
511
512 Object[] args = new Object[] { syntaxOid};
513 method.invoke( checker, args );
514 }
515 catch ( SecurityException e )
516 {
517 NamingException ne = new NamingException( "SyntaxChecker class "+ className
518 + " could not have the oid dependency injected." );
519 ne.setRootCause( e );
520 throw ne;
521 }
522 catch ( NoSuchMethodException e )
523 {
524
525 }
526 catch ( IllegalArgumentException e )
527 {
528 NamingException ne = new NamingException( "SyntaxChecker class "+ className
529 + " could not have the oid dependency injected." );
530 ne.setRootCause( e );
531 throw ne;
532 }
533 catch ( IllegalAccessException e )
534 {
535 NamingException ne = new NamingException( "SyntaxChecker class "+ className
536 + " could not have the oid dependency injected." );
537 ne.setRootCause( e );
538 throw ne;
539 }
540 catch ( InvocationTargetException e )
541 {
542 NamingException ne = new NamingException( "SyntaxChecker class "+ className
543 + " could not have the oid dependency injected." );
544 ne.setRootCause( e );
545 throw ne;
546 }
547 }
548
549
550 public Syntax getSyntax( ServerEntry entry, Registries targetRegistries, String schema ) throws NamingException
551 {
552 String oid = entry.get( MetaSchemaConstants.M_OID_AT ).getString();
553 SyntaxImpl syntax = new SyntaxImpl( oid, targetRegistries.getSyntaxCheckerRegistry() );
554 syntax.setSchema( schema );
555
556 if ( entry.get( MetaSchemaConstants.X_HUMAN_READABLE_AT ) != null )
557 {
558 String val = entry.get( MetaSchemaConstants.X_HUMAN_READABLE_AT ).getString();
559 syntax.setHumanReadable( val.toUpperCase().equals( "TRUE" ) );
560 }
561
562 if ( entry.get( MetaSchemaConstants.M_DESCRIPTION_AT ) != null )
563 {
564 syntax.setDescription( entry.get( MetaSchemaConstants.M_DESCRIPTION_AT ).getString() );
565 }
566
567 return syntax;
568 }
569
570
571 public MatchingRule getMatchingRule( ServerEntry entry, Registries targetRegistries, String schema ) throws NamingException
572 {
573 String oid = entry.get( MetaSchemaConstants.M_OID_AT ).getString();
574 String syntaxOid = entry.get( MetaSchemaConstants.M_SYNTAX_AT ).getString();
575 MatchingRuleImpl mr = new MatchingRuleImpl( oid, syntaxOid, targetRegistries );
576 mr.setSchema( schema );
577 setSchemaObjectProperties( mr, entry );
578 return mr;
579 }
580
581
582 private String[] getStrings( EntryAttribute attr ) throws NamingException
583 {
584 if ( attr == null )
585 {
586 return EMPTY;
587 }
588
589 String[] strings = new String[attr.size()];
590
591 int pos = 0;
592
593 for ( Value<?> value:attr )
594 {
595 strings[pos++] = (String)value.get();
596 }
597
598 return strings;
599 }
600
601
602 public ObjectClass getObjectClass( ServerEntry entry, Registries targetRegistries, String schema ) throws NamingException
603 {
604 String oid = entry.get( MetaSchemaConstants.M_OID_AT ).getString();
605 ObjectClassImpl oc = new ObjectClassImpl( oid, targetRegistries );
606 oc.setSchema( schema );
607
608 if ( entry.get( MetaSchemaConstants.M_SUP_OBJECT_CLASS_AT ) != null )
609 {
610 oc.setSuperClassOids( getStrings( entry.get( MetaSchemaConstants.M_SUP_OBJECT_CLASS_AT ) ) );
611 }
612
613 if ( entry.get( MetaSchemaConstants.M_MAY_AT ) != null )
614 {
615 oc.setMayListOids( getStrings( entry.get( MetaSchemaConstants.M_MAY_AT ) ) );
616 }
617
618 if ( entry.get( MetaSchemaConstants.M_MUST_AT ) != null )
619 {
620 oc.setMustListOids( getStrings( entry.get( MetaSchemaConstants.M_MUST_AT ) ) );
621 }
622
623 if ( entry.get( MetaSchemaConstants.M_TYPE_OBJECT_CLASS_AT ) != null )
624 {
625 String type = entry.get( MetaSchemaConstants.M_TYPE_OBJECT_CLASS_AT ).getString();
626 oc.setType( ObjectClassTypeEnum.getClassType( type ) );
627 }
628 else
629 {
630 oc.setType( ObjectClassTypeEnum.STRUCTURAL );
631 }
632
633 setSchemaObjectProperties( oc, entry );
634
635 return oc;
636 }
637
638
639 public AttributeType getAttributeType( ServerEntry entry, Registries targetRegistries, String schema ) throws NamingException
640 {
641 String oid = entry.get( MetaSchemaConstants.M_OID_AT ).getString();
642 AttributeTypeImpl at = new AttributeTypeImpl( oid, targetRegistries );
643 at.setSchema( schema );
644 setSchemaObjectProperties( at, entry );
645
646 if ( entry.get( MetaSchemaConstants.M_SYNTAX_AT ) != null )
647 {
648 at.setSyntaxOid( entry.get( MetaSchemaConstants.M_SYNTAX_AT ).getString() );
649 }
650
651 if ( entry.get( MetaSchemaConstants.M_EQUALITY_AT ) != null )
652 {
653 at.setEqualityOid( entry.get( MetaSchemaConstants.M_EQUALITY_AT ).getString() );
654 }
655
656 if ( entry.get( MetaSchemaConstants.M_ORDERING_AT ) != null )
657 {
658 at.setOrderingOid( entry.get( MetaSchemaConstants.M_ORDERING_AT ).getString() );
659 }
660
661 if ( entry.get( MetaSchemaConstants.M_SUBSTR_AT ) != null )
662 {
663 at.setSubstrOid( entry.get( MetaSchemaConstants.M_SUBSTR_AT ).getString() );
664 }
665
666 if ( entry.get( MetaSchemaConstants.M_SUP_ATTRIBUTE_TYPE_AT ) != null )
667 {
668 at.setSuperiorOid( entry.get( MetaSchemaConstants.M_SUP_ATTRIBUTE_TYPE_AT ).getString() );
669 }
670
671 if ( entry.get( MetaSchemaConstants.M_COLLECTIVE_AT ) != null )
672 {
673 String val = entry.get( MetaSchemaConstants.M_COLLECTIVE_AT ).getString();
674 at.setCollective( val.equalsIgnoreCase( "TRUE" ) );
675 }
676
677 if ( entry.get( MetaSchemaConstants.M_SINGLE_VALUE_AT ) != null )
678 {
679 String val = entry.get( MetaSchemaConstants.M_SINGLE_VALUE_AT ).getString();
680 at.setSingleValue( val.equalsIgnoreCase( "TRUE" ) );
681 }
682
683 if ( entry.get( MetaSchemaConstants.M_NO_USER_MODIFICATION_AT ) != null )
684 {
685 String val = entry.get( MetaSchemaConstants.M_NO_USER_MODIFICATION_AT ).getString();
686 at.setCanUserModify( ! val.equalsIgnoreCase( "TRUE" ) );
687 }
688
689 if ( entry.get( MetaSchemaConstants.M_USAGE_AT ) != null )
690 {
691 at.setUsage( UsageEnum.getUsage( entry.get( MetaSchemaConstants.M_USAGE_AT ).getString() ) );
692 }
693
694 return at;
695 }
696
697
698 private void setSchemaObjectProperties( MutableSchemaObject mso, ServerEntry entry ) throws NamingException
699 {
700 if ( entry.get( MetaSchemaConstants.M_OBSOLETE_AT ) != null )
701 {
702 String val = entry.get( MetaSchemaConstants.M_OBSOLETE_AT ).getString();
703 mso.setObsolete( val.equalsIgnoreCase( "TRUE" ) );
704 }
705
706 if ( entry.get( MetaSchemaConstants.M_DESCRIPTION_AT ) != null )
707 {
708 mso.setDescription( entry.get( MetaSchemaConstants.M_DESCRIPTION_AT ).getString() );
709 }
710
711 EntryAttribute names = entry.get( MetaSchemaConstants.M_NAME_AT );
712
713 if ( names != null )
714 {
715 List<String> values = new ArrayList<String>();
716
717 for ( Value<?> name:names )
718 {
719 values.add( (String)name.get() );
720 }
721
722 mso.setNames( values.toArray( EMPTY ) );
723 }
724 }
725 }