You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by er...@apache.org on 2006/12/10 22:15:26 UTC
svn commit: r485262 - in /directory/trunks/shared/ldap: ./ src/main/antlr/
src/main/java/org/apache/directory/shared/ldap/schema/syntax/
src/test/java/org/apache/directory/shared/ldap/schema/syntax/
Author: ersiner
Date: Sun Dec 10 13:15:25 2006
New Revision: 485262
URL: http://svn.apache.org/viewvc?view=rev&rev=485262
Log:
Applying Stefan Seelmann's patch for DIRSERVER-793.
Thank you Stefan!
Added:
directory/trunks/shared/ldap/src/main/antlr/schema-extension.g
directory/trunks/shared/ldap/src/main/antlr/schema-qdstring.g
directory/trunks/shared/ldap/src/main/antlr/schema-value.g
directory/trunks/shared/ldap/src/main/antlr/schema.g
directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/schema/syntax/ObjectClassDescription.java
directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/schema/syntax/ObjectClassDescriptionSyntaxChecker.java
directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/schema/syntax/SchemaParser.java
directory/trunks/shared/ldap/src/test/java/org/apache/directory/shared/ldap/schema/syntax/ObjectClassDescriptionSyntaxCheckerTest.java
directory/trunks/shared/ldap/src/test/java/org/apache/directory/shared/ldap/schema/syntax/SchemaParserObjectClassDescriptionTest.java
Modified:
directory/trunks/shared/ldap/pom.xml
Modified: directory/trunks/shared/ldap/pom.xml
URL: http://svn.apache.org/viewvc/directory/trunks/shared/ldap/pom.xml?view=diff&rev=485262&r1=485261&r2=485262
==============================================================================
--- directory/trunks/shared/ldap/pom.xml (original)
+++ directory/trunks/shared/ldap/pom.xml Sun Dec 10 13:15:25 2006
@@ -115,7 +115,7 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antlr-plugin</artifactId>
<configuration>
- <grammars>filter-value-lexer.g filter-lexer.g filter-lexer.g filter-value-parser.g filter-parser.g subtree-specification.g ACIItem.g TriggerSpecification.g</grammars>
+ <grammars>schema-value.g schema-qdstring.g schema-extension.g schema.g filter-value-lexer.g filter-lexer.g filter-lexer.g filter-value-parser.g filter-parser.g subtree-specification.g ACIItem.g TriggerSpecification.g</grammars>
</configuration>
<executions>
<execution>
Added: directory/trunks/shared/ldap/src/main/antlr/schema-extension.g
URL: http://svn.apache.org/viewvc/directory/trunks/shared/ldap/src/main/antlr/schema-extension.g?view=auto&rev=485262
==============================================================================
--- directory/trunks/shared/ldap/src/main/antlr/schema-extension.g (added)
+++ directory/trunks/shared/ldap/src/main/antlr/schema-extension.g Sun Dec 10 13:15:25 2006
@@ -0,0 +1,108 @@
+header {
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.directory.shared.ldap.schema.syntax;
+
+import java.io.* ;
+import java.util.* ;
+
+}
+
+
+
+/**
+ * An antlr generated schema lexer. This is a sub-lexer.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+class AntlrSchemaExtensionLexer extends Lexer;
+
+options {
+ k = 2 ;
+ exportVocab=AntlrSchemaExtension ;
+ charVocabulary = '\u0000'..'\uFFFE';
+ caseSensitive = true ;
+ defaultErrorHandler = false ;
+}
+
+protected WHSP : (options{greedy=true;}: ' ' )+ {$setType(Token.SKIP);} ;
+protected QUOTE : '\'' ;
+//protected ESC : '\\' ;
+
+XKEY : xstring:XSTRING { setText(xstring.getText().trim()); };
+XVALUES : values:VALUES { setText(values.getText().trim()); };
+
+protected XSTRING : ( "X-" ( 'a'..'z' | 'A'..'Z' | '-' | '_' )+ WHSP ) ;
+protected VALUES : ( VALUE | '(' VALUE ( ('$')? VALUE )* ')' ) ;
+protected VALUE : (WHSP)? ( QUOTED_STRING ) (options {greedy=true;}: WHSP)? ;
+protected QUOTED_STRING : ( QUOTE (~'\'')* QUOTE ) ;
+
+
+
+
+
+
+/**
+ * An antlr generated schema parser. This is a sub-parser used to parse
+ * extensions according to RFC4512.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+class AntlrSchemaExtensionParser extends Parser;
+options {
+ k = 3 ;
+ defaultErrorHandler = false ;
+ //buildAST=true ;
+}
+
+
+ /**
+ * extensions = *( SP xstring SP qdstrings )
+ * xstring = "X" HYPHEN 1*( ALPHA / HYPHEN / USCORE )
+ */
+extension returns [AntlrSchemaParser.Extension extension = new AntlrSchemaParser.Extension()]
+ :
+ ( xkey:XKEY { extension.setKey(xkey.getText()); } )
+ ( xvalues:XVALUES { extension.setValues(qdstrings(xvalues.getText())); } )
+ ;
+
+
+qdstrings [String s] returns [List<String> qdstrings]
+ {
+ try
+ {
+ AntlrSchemaQdstringLexer lexer = new AntlrSchemaQdstringLexer(new StringReader(s));
+ AntlrSchemaQdstringParser parser = new AntlrSchemaQdstringParser(lexer);
+ qdstrings = parser.qdstrings();
+ }
+ catch (RecognitionException re) {
+ re.printStackTrace();
+ throw re;
+ }
+ catch (TokenStreamException tse) {
+ tse.printStackTrace();
+ throw tse;
+ }
+ }
+ :
+ ;
+
Added: directory/trunks/shared/ldap/src/main/antlr/schema-qdstring.g
URL: http://svn.apache.org/viewvc/directory/trunks/shared/ldap/src/main/antlr/schema-qdstring.g?view=auto&rev=485262
==============================================================================
--- directory/trunks/shared/ldap/src/main/antlr/schema-qdstring.g (added)
+++ directory/trunks/shared/ldap/src/main/antlr/schema-qdstring.g Sun Dec 10 13:15:25 2006
@@ -0,0 +1,126 @@
+header {
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.directory.shared.ldap.schema.syntax;
+
+import java.util.* ;
+
+}
+
+
+/**
+ * An antlr generated schema lexer. This is a sub-lexer.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+class AntlrSchemaQdstringLexer extends Lexer;
+
+options {
+ k = 2 ;
+ exportVocab=AntlrSchemaQdstring ;
+ charVocabulary = '\u0000'..'\uFFFE';
+ caseSensitive = true ;
+ defaultErrorHandler = false ;
+}
+
+WHSP : ( ' ' ) {$setType(Token.SKIP);} ;
+LPAR : '(' ;
+RPAR : ')' ;
+QUOTE : '\'' ;
+QDSTRING : ( QUOTE (~'\'')* QUOTE ) ;
+
+
+
+
+
+/**
+ * An antlr generated schema parser. This is a sub-parser used to parse
+ * qdstring and qdstrings according to RFC4512.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+class AntlrSchemaQdstringParser extends Parser;
+options {
+ k = 3 ;
+ defaultErrorHandler = false ;
+ //buildAST=true ;
+}
+
+ /**
+ * qdstrings = qdstring / ( LPAREN WSP qdstringlist WSP RPAREN )
+ * qdstringlist = [ qdstring *( SP qdstring ) ]
+ */
+qdstrings returns [List<String> qdstrings]
+ {
+ qdstrings = new ArrayList<String>();
+ String qdstring = null;
+ }
+ :
+ (
+ (
+ q:QDSTRING
+ {
+ qdstring = q.getText();
+ if(qdstring.startsWith("'")) {
+ qdstring = qdstring.substring(1, qdstring.length());
+ }
+ if(qdstring.endsWith("'")) {
+ qdstring = qdstring.substring(0, qdstring.length()-1);
+ }
+ qdstrings.add(qdstring);
+ }
+ )
+ |
+ ( LPAR qdstring=qdstring { qdstrings.add(qdstring); } ( qdstring=qdstring { qdstrings.add(qdstring); } )* RPAR )
+ )
+ ;
+
+ /**
+ * qdstring = SQUOTE dstring SQUOTE
+ * dstring = 1*( QS / QQ / QUTF8 ) ; escaped UTF-8 string
+ *
+ * QQ = ESC %x32 %x37 ; "\27"
+ * QS = ESC %x35 ( %x43 / %x63 ) ; "\5C" / "\5c"
+ *
+ * ; Any UTF-8 encoded Unicode character
+ * ; except %x27 ("\'") and %x5C ("\")
+ * QUTF8 = QUTF1 / UTFMB
+ *
+ * ; Any ASCII character except %x27 ("\'") and %x5C ("\")
+ * QUTF1 = %x00-26 / %x28-5B / %x5D-7F
+ */
+qdstring returns [String qdstring=null]
+ :
+ (
+ q:QDSTRING
+ {
+ qdstring = q.getText();
+ if(qdstring.startsWith("'")) {
+ qdstring = qdstring.substring(1, qdstring.length());
+ }
+ if(qdstring.endsWith("'")) {
+ qdstring = qdstring.substring(0, qdstring.length()-1);
+ }
+ }
+ )
+ ;
+
Added: directory/trunks/shared/ldap/src/main/antlr/schema-value.g
URL: http://svn.apache.org/viewvc/directory/trunks/shared/ldap/src/main/antlr/schema-value.g?view=auto&rev=485262
==============================================================================
--- directory/trunks/shared/ldap/src/main/antlr/schema-value.g (added)
+++ directory/trunks/shared/ldap/src/main/antlr/schema-value.g Sun Dec 10 13:15:25 2006
@@ -0,0 +1,182 @@
+header {
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.directory.shared.ldap.schema.syntax;
+
+import java.util.* ;
+
+}
+
+
+/**
+ * An antlr generated schema lexer. This is a sub-lexer.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+class AntlrSchemaValueLexer extends Lexer;
+
+options {
+ k = 2 ;
+ exportVocab=AntlrSchemaValue ;
+ charVocabulary = '\3'..'\377' ;
+ caseSensitive = true ;
+ defaultErrorHandler = false ;
+}
+
+//WHSP : (' ') {$setType(Token.SKIP);} ;
+SP : ( ' ' )+ { setText(" "); };
+
+LPAR : '(' ;
+RPAR : ')' ;
+
+QUOTE : '\'' ;
+DOLLAR : '$' ;
+LBRACKET : '{' ;
+RBRACKET : '}' ;
+LEN : LBRACKET (DIGIT)+ RBRACKET ;
+DIGIT : ('0'..'9') ;
+NUMERICOID : ('0'..'9')+ ( '.' ('0'..'9')+ )+ ;
+DESCR : ( 'a'..'z' | 'A'..'Z' ) ( 'a'..'z' | 'A'..'Z' | '0'..'9' | '-' )* ;
+
+
+
+
+
+/**
+ * An antlr generated schema parser. This is a sub-parser used to parse
+ * numericoid, oid, oids, qdescr, qdescrs according to RFC4512.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+class AntlrSchemaValueParser extends Parser;
+options {
+ k = 3 ;
+ defaultErrorHandler = false ;
+ //buildAST=true ;
+}
+
+
+ /**
+ * numericoid = number 1*( DOT number )
+ */
+numericoid returns [String numericoid=null]
+ :
+ (
+ (SP)? n:NUMERICOID (SP)? { numericoid = n.getText(); }
+ )
+ ;
+
+
+ /**
+ * oid = descr / numericoid
+ * numericoid = number 1*( DOT number )
+ * descr = keystring
+ * keystring = leadkeychar *keychar
+ * leadkeychar = ALPHA
+ * keychar = ALPHA / DIGIT / HYPHEN
+ * number = DIGIT / ( LDIGIT 1*DIGIT )
+ *
+ */
+oid returns [String oid=null]
+ :
+ (
+ (SP)?
+ (
+ n:NUMERICOID { oid = n.getText(); }
+ |
+ d:DESCR { oid = d.getText(); }
+ )
+ (SP)?
+ )
+ ;
+
+
+ /**
+ * oids = oid / ( LPAREN WSP oidlist WSP RPAREN )
+ * oidlist = oid *( WSP DOLLAR WSP oid )
+ */
+oids returns [List<String> oids]
+ {
+ oids = new ArrayList<String>();
+ String oid = null;
+ }
+ :
+ (
+ (
+ oid=oid { oids.add(oid); }
+ )
+ |
+ (
+ LPAR
+ oid=oid { oids.add(oid); }
+ (
+ DOLLAR
+ oid=oid { oids.add(oid); }
+ )*
+ RPAR
+ )
+ )
+ ;
+
+
+ /**
+ * qdescr = SQUOTE descr SQUOTE
+ */
+qdescr returns [String qdescr=null]
+ :
+ (
+ (SP)?
+ QUOTE
+ d:DESCR { qdescr = d.getText(); }
+ QUOTE
+ )
+ ;
+
+
+ /**
+ * qdescrs = qdescr / ( LPAREN WSP qdescrlist WSP RPAREN )
+ * qdescrlist = [ qdescr *( SP qdescr ) ]
+ */
+qdescrs returns [List<String> qdescrs]
+ {
+ qdescrs = new ArrayList<String>();
+ String qdescr = null;
+ }
+ :
+ (
+ (
+ qdescr=qdescr { qdescrs.add(qdescr); }
+ )
+ |
+ (
+ LPAR
+ qdescr=qdescr { qdescrs.add(qdescr); }
+ (
+ SP
+ qdescr=qdescr { qdescrs.add(qdescr); }
+ )*
+ (SP)?
+ RPAR
+ )
+ )
+ ;
+
Added: directory/trunks/shared/ldap/src/main/antlr/schema.g
URL: http://svn.apache.org/viewvc/directory/trunks/shared/ldap/src/main/antlr/schema.g?view=auto&rev=485262
==============================================================================
--- directory/trunks/shared/ldap/src/main/antlr/schema.g (added)
+++ directory/trunks/shared/ldap/src/main/antlr/schema.g Sun Dec 10 13:15:25 2006
@@ -0,0 +1,276 @@
+header {
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.directory.shared.ldap.schema.syntax;
+
+import java.io.* ;
+import java.util.* ;
+
+}
+
+/**
+ * An antlr generated schema main lexer.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+class AntlrSchemaLexer extends Lexer;
+
+options {
+ k = 5 ;
+ exportVocab=AntlrSchema ;
+ charVocabulary = '\u0000'..'\uFFFE';
+ caseSensitive = true ;
+ defaultErrorHandler = false ;
+}
+
+WHSP : (options{greedy=true;}: ' ' )+ {$setType(Token.SKIP);} ;
+
+LPAR : '(' ;
+RPAR : ')' ;
+QUOTE : '\'' ;
+DOLLAR : '$' ;
+LBRACKET : '{' ;
+RBRACKET : '}' ;
+
+LEN : LBRACKET ('0'..'9')+ RBRACKET ;
+
+USERAPPLICATIONS : "userApplications" ;
+DIRECTORYOPERATION : "directoryOperation" ;
+DISTRIBUTEDOPERATION : "distributedOperation" ;
+DSAOPERATION : "dSAOperation" ;
+
+SINGLE_VALUE : ( "SINGLE-VALUE" (WHSP)? ) ;
+COLLECTIVE : ( "COLLECTIVE" (WHSP)? ) ;
+NO_USER_MODIFICATION : ( "NO-USER-MODIFICATION" (WHSP)? ) ;
+
+OBSOLETE : ( "OBSOLETE" (WHSP)? ) ;
+ABSTRACT : ( "ABSTRACT" (WHSP)? ) ;
+STRUCTURAL : ( "STRUCTURAL" (WHSP)? ) ;
+AUXILIARY : ( "AUXILIARY" (WHSP)? ) ;
+
+STARTNUMERICOID : ( LPAR ( numericoid:VALUE ) ) { setText(numericoid.getText().trim()); } ;
+NAME : ( "NAME" WHSP qdstrings:VALUES ) { setText(qdstrings.getText().trim()); } ;
+DESC : ( "DESC" WHSP qdstring:VALUES ) { setText(qdstring.getText().trim()); } ;
+SUP : ( "SUP" WHSP sup:VALUES ) { setText(sup.getText().trim()); } ;
+MUST : ( "MUST" WHSP must:VALUES ) { setText(must.getText().trim()); } ;
+MAY : ( "MAY" WHSP may:VALUES ) { setText(may.getText()); } ;
+EQUALITY : ( "EQUALITY" WHSP equality:VALUES ) { setText(equality.getText().trim()); } ;
+ORDERING : ( "ORDERING" WHSP ordering:VALUES ) { setText(ordering.getText().trim()); } ;
+SUBSTR : ( "SUBSTR" WHSP substr:VALUES ) { setText(substr.getText().trim()); } ;
+SYNTAX : ( "SYNTAX" WHSP syntax:VALUES (len:LEN)? ) { setText(syntax.getText().trim() + (len!=null?len.getText().trim():"")); } ;
+USAGE : ( "USAGE" WHSP op:VALUES ) { setText(op.getText().trim()); } ;
+APPLIES : ( "APPLIES" WHSP applies:VALUES ) { setText(applies.getText().trim()); } ;
+EXTENSION : x:( "X-" ( 'a'..'z' | 'A'..'Z' | '-' | '_' )+ WHSP VALUES ) ;
+
+protected VALUES : ( VALUE | LPAR VALUE ( (DOLLAR)? VALUE )* RPAR ) ;
+protected VALUE : (WHSP)? ( QUOTED_STRING | UNQUOTED_STRING ) (options {greedy=true;}: WHSP)? ;
+protected UNQUOTED_STRING : (options{greedy=true;}: 'a'..'z' | 'A'..'Z' | '0'..'9' | '-' | ';' | '.' )+ ;
+protected QUOTED_STRING : ( QUOTE (~'\'')* QUOTE ) ;
+
+
+/**
+ * An antlr generated schema main parser.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+class AntlrSchemaParser extends Parser;
+options {
+ k = 3 ;
+ defaultErrorHandler = false ;
+ //buildAST=true ;
+}
+
+{
+ static class Extension
+ {
+
+ private String key;
+
+ private List<String> values;
+
+ public Extension()
+ {
+ this.key = "";
+ this.values = new ArrayList<String>();
+ }
+
+ public String getKey()
+ {
+ return key;
+ }
+
+ public void setKey( String key )
+ {
+ this.key = key;
+ }
+
+ public List<String> getValues()
+ {
+ return values;
+ }
+
+ public void setValues( List<String> values )
+ {
+ this.values = values;
+ }
+
+
+ public void addValue( String value )
+ {
+ this.values.add( value );
+ }
+
+ }
+}
+
+
+ /**
+ * Production for matching object class descriptions. It is fault-tolerant
+ * against element ordering.
+ *
+ * <pre>
+ * ObjectClassDescription = LPAREN WSP
+ * numericoid ; object identifier
+ * [ SP "NAME" SP qdescrs ] ; short names (descriptors)
+ * [ SP "DESC" SP qdstring ] ; description
+ * [ SP "OBSOLETE" ] ; not active
+ * [ SP "SUP" SP oids ] ; superior object classes
+ * [ SP kind ] ; kind of class
+ * [ SP "MUST" SP oids ] ; attribute types
+ * [ SP "MAY" SP oids ] ; attribute types
+ * extensions WSP RPAREN
+ *
+ * kind = "ABSTRACT" / "STRUCTURAL" / "AUXILIARY"
+ *
+ * extensions = *( SP xstring SP qdstrings )
+ * xstring = "X" HYPHEN 1*( ALPHA / HYPHEN / USCORE )
+ * </pre>
+ */
+objectClassDescription returns [ObjectClassDescription ocd = new ObjectClassDescription()]
+ :
+ ( oid:STARTNUMERICOID { ocd.setOid(numericoid(oid.getText())); } )
+ (
+ ( name:NAME { ocd.setNames(qdescrs(name.getText())); } )
+ |
+ ( desc:DESC { ocd.setDescription(qdstring(desc.getText())); } )
+ |
+ ( OBSOLETE { ocd.setObsolete( true ); } )
+ |
+ ( sup:SUP { ocd.setSuperiorObjectClasses(oids(sup.getText())); } )
+ |
+ ( ABSTRACT { ocd.setKind( ObjectClassDescription.Kind.ABSTRACT ); }
+ |
+ STRUCTURAL { ocd.setKind( ObjectClassDescription.Kind.STRUCTURAL ); }
+ |
+ AUXILIARY { ocd.setKind( ObjectClassDescription.Kind.AUXILIARY ); }
+ )
+ |
+ ( must:MUST { ocd.setMustAttributeTypes(oids(must.getText())); } )
+ |
+ ( may:MAY { ocd.setMayAttributeTypes(oids(may.getText())); } )
+ |
+ ( extension:EXTENSION {
+ Extension ex = extension(extension.getText());
+ ocd.addExtension(ex.getKey(), ex.getValues());
+ } )
+ )*
+ RPAR
+ ;
+
+
+extension [String s] returns [Extension extension]
+ {
+ extension = new Extension();
+ AntlrSchemaExtensionLexer lexer = new AntlrSchemaExtensionLexer(new StringReader(s));
+ AntlrSchemaExtensionParser parser = new AntlrSchemaExtensionParser(lexer);
+ extension = parser.extension();
+ }
+ :
+ ;
+
+
+numericoid [String s] returns [String numericoid]
+ {
+ AntlrSchemaValueLexer lexer = new AntlrSchemaValueLexer(new StringReader(s));
+ AntlrSchemaValueParser parser = new AntlrSchemaValueParser(lexer);
+ numericoid = parser.numericoid();
+ }
+ :
+ ;
+
+oid [String s] returns [String oid]
+ {
+ AntlrSchemaValueLexer lexer = new AntlrSchemaValueLexer(new StringReader(s));
+ AntlrSchemaValueParser parser = new AntlrSchemaValueParser(lexer);
+ oid = parser.oid();
+ }
+ :
+ ;
+
+oids [String s] returns [List<String> oids]
+ {
+ AntlrSchemaValueLexer lexer = new AntlrSchemaValueLexer(new StringReader(s));
+ AntlrSchemaValueParser parser = new AntlrSchemaValueParser(lexer);
+ oids = parser.oids();
+ }
+ :
+ ;
+
+qdescr [String s] returns [String qdescr]
+ {
+ AntlrSchemaValueLexer lexer = new AntlrSchemaValueLexer(new StringReader(s));
+ AntlrSchemaValueParser parser = new AntlrSchemaValueParser(lexer);
+ qdescr = parser.qdescr();
+ }
+ :
+ ;
+
+qdescrs [String s] returns [List<String> qdescrs]
+ {
+ AntlrSchemaValueLexer lexer = new AntlrSchemaValueLexer(new StringReader(s));
+ AntlrSchemaValueParser parser = new AntlrSchemaValueParser(lexer);
+ qdescrs = parser.qdescrs();
+ }
+ :
+ ;
+
+qdstring [String s] returns [String qdstring]
+ {
+ AntlrSchemaQdstringLexer lexer = new AntlrSchemaQdstringLexer(new StringReader(s));
+ AntlrSchemaQdstringParser parser = new AntlrSchemaQdstringParser(lexer);
+ qdstring = parser.qdstring();
+ }
+ :
+ ;
+
+qdstrings [String s] returns [List<String> qdstrings]
+ {
+ AntlrSchemaQdstringLexer lexer = new AntlrSchemaQdstringLexer(new StringReader(s));
+ AntlrSchemaQdstringParser parser = new AntlrSchemaQdstringParser(lexer);
+ qdstrings = parser.qdstrings();
+ }
+ :
+ ;
+
+
+
+
\ No newline at end of file
Added: directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/schema/syntax/ObjectClassDescription.java
URL: http://svn.apache.org/viewvc/directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/schema/syntax/ObjectClassDescription.java?view=auto&rev=485262
==============================================================================
--- directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/schema/syntax/ObjectClassDescription.java (added)
+++ directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/schema/syntax/ObjectClassDescription.java Sun Dec 10 13:15:25 2006
@@ -0,0 +1,206 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.directory.shared.ldap.schema.syntax;
+
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * RFC 4512 - 4.1.1. Object Class Description
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ObjectClassDescription
+{
+ public static enum Kind
+ {
+ ABSTRACT, STRUCTURAL, AUXILIARY
+ }
+
+ private String oid;
+
+ private List<String> names;
+
+ private String description;
+
+ private boolean isObsolete;
+
+ private List<String> superiorObjectClasses;
+
+ private Kind kind;
+
+ private List<String> mustAttributeTypes;
+
+ private List<String> mayAttributeTypes;
+
+ private Map<String, List<String>> extensions;
+
+
+ public ObjectClassDescription()
+ {
+ this.oid = "";
+ names = new ArrayList<String>();
+ description = "";
+ isObsolete = false;
+ superiorObjectClasses = new ArrayList<String>();
+ kind = Kind.STRUCTURAL;
+ mustAttributeTypes = new ArrayList<String>();
+ mayAttributeTypes = new ArrayList<String>();
+ extensions = new LinkedHashMap<String, List<String>>();
+ }
+
+
+ public String getDescription()
+ {
+ return description;
+ }
+
+
+ public void setDescription( String description )
+ {
+ this.description = description;
+ }
+
+
+ public Map<String, List<String>> getExtensions()
+ {
+ return extensions;
+ }
+
+
+ public void setExtensions( Map<String, List<String>> extensions )
+ {
+ this.extensions = extensions;
+ }
+
+
+ public boolean isObsolete()
+ {
+ return isObsolete;
+ }
+
+
+ public void setObsolete( boolean isObsolete )
+ {
+ this.isObsolete = isObsolete;
+ }
+
+
+ public List<String> getMayAttributeTypes()
+ {
+ return mayAttributeTypes;
+ }
+
+
+ public void setMayAttributeTypes( List<String> mayAttributeTypes )
+ {
+ this.mayAttributeTypes = mayAttributeTypes;
+ }
+
+
+ public List<String> getMustAttributeTypes()
+ {
+ return mustAttributeTypes;
+ }
+
+
+ public void setMustAttributeTypes( List<String> mustAttributeTypes )
+ {
+ this.mustAttributeTypes = mustAttributeTypes;
+ }
+
+
+ public List<String> getNames()
+ {
+ return names;
+ }
+
+
+ public void setNames( List<String> names )
+ {
+ this.names = names;
+ }
+
+
+ public String getNumericOid()
+ {
+ return oid;
+ }
+
+
+ public void setOid( String oid )
+ {
+ this.oid = oid;
+ }
+
+
+ public List<String> getSuperiorObjectClasses()
+ {
+ return superiorObjectClasses;
+ }
+
+
+ public void setSuperiorObjectClasses( List<String> superiorObjectClasses )
+ {
+ this.superiorObjectClasses = superiorObjectClasses;
+ }
+
+
+ public Kind getKind()
+ {
+ return kind;
+ }
+
+
+ public void setKind( Kind kind )
+ {
+ this.kind = kind;
+ }
+
+
+ public void addSuperiorObjectClass( String oid )
+ {
+ this.superiorObjectClasses.add( oid );
+ }
+
+
+ public void addMustAttributeType( String oid )
+ {
+ this.mustAttributeTypes.add( oid );
+ }
+
+
+ public void addMayAttributeType( String oid )
+ {
+ this.mayAttributeTypes.add( oid );
+ }
+
+
+ public void addExtension( String key, List<String> values )
+ {
+ this.extensions.put( key, values );
+ }
+
+}
\ No newline at end of file
Added: directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/schema/syntax/ObjectClassDescriptionSyntaxChecker.java
URL: http://svn.apache.org/viewvc/directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/schema/syntax/ObjectClassDescriptionSyntaxChecker.java?view=auto&rev=485262
==============================================================================
--- directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/schema/syntax/ObjectClassDescriptionSyntaxChecker.java (added)
+++ directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/schema/syntax/ObjectClassDescriptionSyntaxChecker.java Sun Dec 10 13:15:25 2006
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.directory.shared.ldap.schema.syntax;
+
+
+import java.text.ParseException;
+
+import javax.naming.NamingException;
+
+import org.apache.directory.shared.ldap.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.shared.ldap.message.ResultCodeEnum;
+import org.apache.directory.shared.ldap.util.StringTools;
+
+
+/**
+ * A SyntaxChecker which verifies that a value follows the
+ * object class descripton syntax according to RFC 4512, par 4.4.1:
+ *
+ * <pre>
+ * ObjectClassDescription = LPAREN WSP
+ * numericoid ; object identifier
+ * [ SP "NAME" SP qdescrs ] ; short names (descriptors)
+ * [ SP "DESC" SP qdstring ] ; description
+ * [ SP "OBSOLETE" ] ; not active
+ * [ SP "SUP" SP oids ] ; superior object classes
+ * [ SP kind ] ; kind of class
+ * [ SP "MUST" SP oids ] ; attribute types
+ * [ SP "MAY" SP oids ] ; attribute types
+ * extensions WSP RPAREN
+ *
+ * kind = "ABSTRACT" / "STRUCTURAL" / "AUXILIARY"
+ *
+ * extensions = *( SP xstring SP qdstrings )
+ * xstring = "X" HYPHEN 1*( ALPHA / HYPHEN / USCORE )
+ * </pre>
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class ObjectClassDescriptionSyntaxChecker implements SyntaxChecker
+{
+
+ /** The Syntax OID, according to RFC 4517, par. 3.3.24 */
+ public static final String OID = "1.3.6.1.4.1.1466.115.121.1.37";
+
+ private SchemaParser schemaParser;
+
+
+ /**
+ *
+ * Creates a new instance of ObjectClassDescriptionSyntaxChecker.
+ *
+ */
+ public ObjectClassDescriptionSyntaxChecker()
+ {
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.apache.directory.shared.ldap.schema.SyntaxChecker#getSyntaxOid()
+ */
+ public String getSyntaxOid()
+ {
+ return OID;
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.apache.directory.shared.ldap.schema.SyntaxChecker#assertSyntax(java.lang.Object)
+ */
+ public void assertSyntax( Object value ) throws NamingException
+ {
+ if ( !isValidSyntax( value ) )
+ {
+ throw new LdapInvalidAttributeValueException( ResultCodeEnum.INVALID_ATTRIBUTE_SYNTAX );
+ }
+ }
+
+
+ /* (non-Javadoc)
+ * @see org.apache.directory.shared.ldap.schema.SyntaxChecker#isValidSyntax(java.lang.Object)
+ */
+ public boolean isValidSyntax( Object value )
+ {
+ String strValue;
+
+ if ( value == null )
+ {
+ return false;
+ }
+
+ if ( value instanceof String )
+ {
+ strValue = ( String ) value;
+ }
+ else if ( value instanceof byte[] )
+ {
+ strValue = StringTools.utf8ToString( ( byte[] ) value );
+ }
+ else
+ {
+ strValue = value.toString();
+ }
+
+ if ( schemaParser == null )
+ {
+ schemaParser = new SchemaParser();
+ }
+
+ try
+ {
+ schemaParser.parseObjectClassDescription( strValue );
+ return true;
+ }
+ catch ( ParseException pe )
+ {
+ return false;
+ }
+ }
+}
Added: directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/schema/syntax/SchemaParser.java
URL: http://svn.apache.org/viewvc/directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/schema/syntax/SchemaParser.java?view=auto&rev=485262
==============================================================================
--- directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/schema/syntax/SchemaParser.java (added)
+++ directory/trunks/shared/ldap/src/main/java/org/apache/directory/shared/ldap/schema/syntax/SchemaParser.java Sun Dec 10 13:15:25 2006
@@ -0,0 +1,214 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.directory.shared.ldap.schema.syntax;
+
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.text.ParseException;
+
+import antlr.CharBuffer;
+import antlr.LexerSharedInputState;
+import antlr.RecognitionException;
+import antlr.TokenStream;
+import antlr.TokenStreamException;
+
+
+/**
+ * A parser for RFC 4512 schema objects
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SchemaParser
+{
+
+ /** the antlr generated parser being wrapped */
+ private ReusableAntlrSchemaParser parser;
+
+ /** the antlr generated lexer being wrapped */
+ private ReusableAntlrSchemaLexer lexer;
+
+
+ /**
+ * Creates a schema parser instance.
+ */
+ public SchemaParser()
+ {
+ this.lexer = new ReusableAntlrSchemaLexer( new StringReader( "" ) );
+ this.parser = new ReusableAntlrSchemaParser( lexer );
+ }
+
+
+ /**
+ * Initializes the plumbing by creating a pipe and coupling the parser/lexer
+ * pair with it. param spec the specification to be parsed
+ */
+ private synchronized void reset( String spec )
+ {
+ StringReader in = new StringReader( spec );
+ this.lexer.prepareNextInput( in );
+ this.parser.resetState();
+ }
+
+
+ /**
+ * Parses a object class definition according to RFC 4512:
+ *
+ * <pre>
+ * ObjectClassDescription = LPAREN WSP
+ * numericoid ; object identifier
+ * [ SP "NAME" SP qdescrs ] ; short names (descriptors)
+ * [ SP "DESC" SP qdstring ] ; description
+ * [ SP "OBSOLETE" ] ; not active
+ * [ SP "SUP" SP oids ] ; superior object classes
+ * [ SP kind ] ; kind of class
+ * [ SP "MUST" SP oids ] ; attribute types
+ * [ SP "MAY" SP oids ] ; attribute types
+ * extensions WSP RPAREN
+ *
+ * kind = "ABSTRACT" / "STRUCTURAL" / "AUXILIARY"
+ *
+ * extensions = *( SP xstring SP qdstrings )
+ * xstring = "X" HYPHEN 1*( ALPHA / HYPHEN / USCORE )
+ * </pre>
+ *
+ * @param objectClassDescription the object class description to be parsed
+ * @return the parsed ObjectClassDescription bean
+ * @throws ParseException if there are any recognition errors (bad syntax)
+ */
+ public synchronized ObjectClassDescription parseObjectClassDescription( String objectClassDescription )
+ throws ParseException
+ {
+
+ if ( objectClassDescription == null )
+ {
+ throw new ParseException( "Null", 0 );
+ }
+
+ reset( objectClassDescription ); // reset and initialize the parser / lexer pair
+
+ try
+ {
+ ObjectClassDescription ocd = parser.objectClassDescription();
+ return ocd;
+ }
+ catch ( RecognitionException re )
+ {
+ String msg = "Parser failure on object class description:\n\t" + objectClassDescription;
+ msg += "\nAntlr message: " + re.getMessage();
+ msg += "\nAntlr column: " + re.getColumn();
+ throw new ParseException( msg, re.getColumn() );
+ }
+ catch ( TokenStreamException tse )
+ {
+ String msg = "Parser failure on object class description:\n\t" + objectClassDescription;
+ msg += "\nAntlr message: " + tse.getMessage();
+ throw new ParseException( msg, 0 );
+ }
+
+ }
+
+ /**
+ * A reusable lexer class extended from antlr generated lexer for an LDAP
+ * schema as defined in RFC 4512. This class
+ * enables the reuse of the antlr lexer without having to recreate the it every
+ * time as stated in <a
+ * href="http://www.antlr.org:8080/pipermail/antlr-interest/2003-April/003631.html">
+ * a Antlr Interest Group mail</a> .
+ *
+ * @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev: 437007 $
+ */
+ class ReusableAntlrSchemaLexer extends AntlrSchemaLexer
+ {
+ private boolean savedCaseSensitive;
+
+ private boolean savedCaseSensitiveLiterals;
+
+
+ /**
+ * Creates a ReusableAntlrSchemaLexer instance.
+ *
+ * @param in
+ * the input to the lexer
+ */
+ public ReusableAntlrSchemaLexer( Reader in )
+ {
+ super( in );
+ savedCaseSensitive = getCaseSensitive();
+ savedCaseSensitiveLiterals = getCaseSensitiveLiterals();
+ }
+
+
+ /**
+ * Resets the state of an antlr lexer and initializes it with new input.
+ *
+ * @param in
+ * the input to the lexer
+ */
+ public void prepareNextInput( Reader in )
+ {
+ CharBuffer buf = new CharBuffer( in );
+ LexerSharedInputState state = new LexerSharedInputState( buf );
+ this.setInputState( state );
+
+ this.setCaseSensitive( savedCaseSensitive );
+
+ // no set method for this protected field.
+ this.caseSensitiveLiterals = savedCaseSensitiveLiterals;
+ }
+ }
+
+ /**
+ * A reusable parser class extended from antlr generated parser for an LDAP
+ * schema as defined in RFC 4512. This class
+ * enables the reuse of the antlr parser without having to recreate the it every
+ * time as stated in <a
+ * href="http://www.antlr.org:8080/pipermail/antlr-interest/2003-April/003631.html">
+ * a Antlr Interest Group mail</a> .
+ *
+ * @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a>
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev: 437007 $
+ */
+ class ReusableAntlrSchemaParser extends AntlrSchemaParser
+ {
+ /**
+ * Creates a ReusableAntlrSchemaParser instance.
+ */
+ public ReusableAntlrSchemaParser( TokenStream lexer )
+ {
+ super( lexer );
+ }
+
+
+ /**
+ * Resets the state of an antlr parser.
+ */
+ public void resetState()
+ {
+ // no set method for this protected field.
+ this.traceDepth = 0;
+
+ this.getInputState().reset();
+ }
+ }
+}
Added: directory/trunks/shared/ldap/src/test/java/org/apache/directory/shared/ldap/schema/syntax/ObjectClassDescriptionSyntaxCheckerTest.java
URL: http://svn.apache.org/viewvc/directory/trunks/shared/ldap/src/test/java/org/apache/directory/shared/ldap/schema/syntax/ObjectClassDescriptionSyntaxCheckerTest.java?view=auto&rev=485262
==============================================================================
--- directory/trunks/shared/ldap/src/test/java/org/apache/directory/shared/ldap/schema/syntax/ObjectClassDescriptionSyntaxCheckerTest.java (added)
+++ directory/trunks/shared/ldap/src/test/java/org/apache/directory/shared/ldap/schema/syntax/ObjectClassDescriptionSyntaxCheckerTest.java Sun Dec 10 13:15:25 2006
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.directory.shared.ldap.schema.syntax;
+
+
+import junit.framework.TestCase;
+
+
+/**
+ * Test cases for ObjectClassDescriptionSyntaxChecker.
+ *
+ * There are also many test cases in SchemaParserObjectClassDescriptionTest.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ * @version $Rev$
+ */
+public class ObjectClassDescriptionSyntaxCheckerTest extends TestCase
+{
+ ObjectClassDescriptionSyntaxChecker checker = new ObjectClassDescriptionSyntaxChecker();
+
+
+ public void testNullString()
+ {
+ assertFalse( checker.isValidSyntax( null ) );
+ }
+
+
+ public void testEmptyString()
+ {
+ assertFalse( checker.isValidSyntax( "" ) );
+ }
+
+
+ public void testOneCharString()
+ {
+ assertFalse( checker.isValidSyntax( "A" ) );
+ assertFalse( checker.isValidSyntax( "1" ) );
+ assertFalse( checker.isValidSyntax( "-" ) );
+ assertFalse( checker.isValidSyntax( "(" ) );
+ }
+
+
+ public void testValid()
+ {
+ assertTrue( checker.isValidSyntax( "( 2.5.6.6 )" ) );
+ assertTrue( checker.isValidSyntax( "( 2.5.6.6 NAME 'person' )" ) );
+ assertTrue( checker.isValidSyntax( "( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' )" ) );
+ assertTrue( checker.isValidSyntax( "( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP top )" ) );
+ assertTrue( checker.isValidSyntax( "( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP top STRUCTURAL )" ) );
+ assertTrue( checker.isValidSyntax( "( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP top STRUCTURAL MUST ( sn $ cn ) )" ) );
+ assertTrue( checker.isValidSyntax( "( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP top STRUCTURAL MUST ( sn $ cn ) MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )" ) );
+
+ assertTrue( checker.isValidSyntax( "(2.5.6.6)" ) );
+ assertTrue( checker.isValidSyntax( "( 2.5.6.6 NAME 'person' )" ) );
+ }
+
+
+ public void testInvalid()
+ {
+ // missing/invalid OID
+ assertFalse( checker.isValidSyntax( "()" ) );
+ assertFalse( checker.isValidSyntax( "( )" ) );
+ assertFalse( checker.isValidSyntax( "( . )" ) );
+ assertFalse( checker.isValidSyntax( "( 1 )" ) );
+ assertFalse( checker.isValidSyntax( "( 1. )" ) );
+ assertFalse( checker.isValidSyntax( "( 1.2. )" ) );
+ assertFalse( checker.isValidSyntax( "( 1.A )" ) );
+ assertFalse( checker.isValidSyntax( "( A.B )" ) );
+
+ // missing right parenthesis
+ assertFalse( checker.isValidSyntax( "( 2.5.6.6 NAME 'person'" ) );
+
+ // missing quotes
+ assertFalse( checker.isValidSyntax( "( 2.5.6.6 NAME person )" ) );
+
+ // lowercase NAME, DESC, SUP
+ assertFalse( checker.isValidSyntax( "( 2.5.6.6 name 'person' desc 'RFC2256: a person' sup top " ) );
+
+ }
+
+}
Added: directory/trunks/shared/ldap/src/test/java/org/apache/directory/shared/ldap/schema/syntax/SchemaParserObjectClassDescriptionTest.java
URL: http://svn.apache.org/viewvc/directory/trunks/shared/ldap/src/test/java/org/apache/directory/shared/ldap/schema/syntax/SchemaParserObjectClassDescriptionTest.java?view=auto&rev=485262
==============================================================================
--- directory/trunks/shared/ldap/src/test/java/org/apache/directory/shared/ldap/schema/syntax/SchemaParserObjectClassDescriptionTest.java (added)
+++ directory/trunks/shared/ldap/src/test/java/org/apache/directory/shared/ldap/schema/syntax/SchemaParserObjectClassDescriptionTest.java Sun Dec 10 13:15:25 2006
@@ -0,0 +1,1072 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.directory.shared.ldap.schema.syntax;
+
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.directory.shared.ldap.schema.syntax.ObjectClassDescription;
+import org.apache.directory.shared.ldap.schema.syntax.SchemaParser;
+
+
+/**
+ * Tests the SchemaParser class.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class SchemaParserObjectClassDescriptionTest extends TestCase
+{
+ /** the parser instance */
+ private SchemaParser parser;
+
+ /** holds multithreaded success value */
+ boolean isSuccessMultithreaded = true;
+
+
+ protected void setUp() throws Exception
+ {
+ parser = new SchemaParser();
+ }
+
+
+ protected void tearDown() throws Exception
+ {
+ parser = null;
+ }
+
+
+ /**
+ * Test numericoid
+ *
+ * @throws ParseException
+ */
+ public void testNumericOid() throws ParseException
+ {
+ String value = null;
+ ObjectClassDescription ocd = null;
+
+ // null test
+ value = null;
+ try
+ {
+ parser.parseObjectClassDescription( value );
+ fail( "Exception expected, null" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+
+ // no oid
+ value = "( )";
+ try
+ {
+ parser.parseObjectClassDescription( value );
+ fail( "Exception expected, no NUMERICOID" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+
+ // simple
+ value = "( 1.1 )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( "1.1", ocd.getNumericOid() );
+
+ // simple with spaces
+ value = "( 1.1 )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( "1.1", ocd.getNumericOid() );
+
+ // non-numeric not allowed
+ value = "( top )";
+ try
+ {
+ parser.parseObjectClassDescription( value );
+ fail( "Exception expected, invalid NUMERICOID top" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+
+ // to short
+ value = "( 1 )";
+ try
+ {
+ parser.parseObjectClassDescription( value );
+ fail( "Exception expected, invalid NUMERICOID 1" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+
+ // dot only
+ value = "( . )";
+ try
+ {
+ parser.parseObjectClassDescription( value );
+ fail( "Exception expected, invalid NUMERICOID ." );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+
+ // ends with dot
+ value = "( 1.1. )";
+ try
+ {
+ parser.parseObjectClassDescription( value );
+ fail( "Exception expected, invalid NUMERICOID 1.1." );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+
+ // quotes not allowed
+ value = "( '1.1' )";
+ try
+ {
+ parser.parseObjectClassDescription( value );
+ fail( "Exception expected, invalid NUMERICOID '1.1' (quoted)" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+ }
+
+
+ /**
+ * Tests NAME and its values
+ *
+ * @throws ParseException
+ */
+ public void testNames() throws ParseException
+ {
+ String value = null;
+ ObjectClassDescription ocd = null;
+
+ // alpha
+ value = "( 1.1 NAME 'test' )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 1, ocd.getNames().size() );
+ assertEquals( "test", ocd.getNames().get( 0 ) );
+
+ // alpha-num-hypen
+ value = "( 1.1 NAME 'a-z-0-9' )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 1, ocd.getNames().size() );
+ assertEquals( "a-z-0-9", ocd.getNames().get( 0 ) );
+
+ // with parentheses
+ value = "( 1.1 NAME ( 'a-z-0-9' ) )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 1, ocd.getNames().size() );
+ assertEquals( "a-z-0-9", ocd.getNames().get( 0 ) );
+
+ // with parentheses, without space
+ value = "( 1.1 NAME ('a-z-0-9') )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 1, ocd.getNames().size() );
+ assertEquals( "a-z-0-9", ocd.getNames().get( 0 ) );
+
+ // multi with space
+ value = "( 1.1 NAME ( 'test' 'a-z-0-9' ) )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 2, ocd.getNames().size() );
+ assertEquals( "test", ocd.getNames().get( 0 ) );
+ assertEquals( "a-z-0-9", ocd.getNames().get( 1 ) );
+
+ // multi without space
+ value = "( 1.1 NAME ('test' 'a-z-0-9' 'top') )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 3, ocd.getNames().size() );
+ assertEquals( "test", ocd.getNames().get( 0 ) );
+ assertEquals( "a-z-0-9", ocd.getNames().get( 1 ) );
+ assertEquals( "top", ocd.getNames().get( 2 ) );
+
+ // multi with many spaces
+ value = "( 1.1 NAME ( 'test' 'a-z-0-9' 'top' ) )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 3, ocd.getNames().size() );
+ assertEquals( "test", ocd.getNames().get( 0 ) );
+ assertEquals( "a-z-0-9", ocd.getNames().get( 1 ) );
+ assertEquals( "top", ocd.getNames().get( 2 ) );
+
+ // lowercase
+ value = "( 1.1 name 'test' )";
+ try
+ {
+ parser.parseObjectClassDescription( value );
+ fail( "Exception expected, NAME is lowercase" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+
+ // unquoted
+ value = "( 1.1 NAME test )";
+ try
+ {
+ parser.parseObjectClassDescription( value );
+ fail( "Exception expected, invalid NAME test (unquoted)" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+
+ // start with number
+ value = "( 1.1 NAME '1test' )";
+ try
+ {
+ parser.parseObjectClassDescription( value );
+ fail( "Exception expected, invalid NAME 1test (starts with number)" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+
+ // start with hypen
+ value = "( 1.1 NAME '-test' )";
+ try
+ {
+ parser.parseObjectClassDescription( value );
+ fail( "Exception expected, invalid NAME -test (starts with hypen)" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+
+ // invalid character
+ value = "( 1.1 NAME 'te_st' )";
+ try
+ {
+ parser.parseObjectClassDescription( value );
+ fail( "Exception expected, invalid NAME te_st (contains invalid character)" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+
+ // NAM unknown
+ value = "( 1.1 NAM 'test' )";
+ try
+ {
+ parser.parseObjectClassDescription( value );
+ fail( "Exception expected, invalid token NAM" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+
+ // one valid, one invalid
+ value = "( 1.1 NAME ( 'test' 'te_st' ) )";
+ try
+ {
+ parser.parseObjectClassDescription( value );
+ fail( "Exception expected, invalid NAME te_st (contains invalid character)" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+
+ // no space between values
+ value = "( 1.1 NAME ( 'test''test2' ) )";
+ try
+ {
+ ocd = parser.parseObjectClassDescription( value );
+ fail( "Exception expected, invalid NAME values (no space between values)" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+ }
+
+
+ /**
+ * Tests DESC
+ *
+ * @throws ParseException
+ */
+ public void testDescription() throws ParseException
+ {
+ String value = null;
+ ObjectClassDescription ocd = null;
+
+ // simple
+ value = "(1.1 NAME 'test' DESC 'Descripton')";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( "Descripton", ocd.getDescription() );
+
+ // unicode
+ value = "( 1.1 NAME 'test' DESC 'Descripton äöüà é¨é·' )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( "Descripton äöüà é¨é·", ocd.getDescription() );
+
+ // lowercase
+ value = "( 1.1 desc 'Descripton' )";
+ try
+ {
+ parser.parseObjectClassDescription( value );
+ fail( "Exception expected, DESC is lowercase" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+ }
+
+
+ /**
+ * Tests OBSOLETE
+ *
+ * @throws ParseException
+ */
+ public void testObsolete() throws ParseException
+ {
+ String value = null;
+ ObjectClassDescription ocd = null;
+
+ // not obsolete
+ value = "( 1.1 NAME 'test' DESC 'Descripton' )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertFalse( ocd.isObsolete() );
+
+ // obsolete
+ value = "(1.1 NAME 'test' DESC 'Descripton' OBSOLETE)";
+ ocd = parser.parseObjectClassDescription( value );
+ assertTrue( ocd.isObsolete() );
+
+ // ivalid
+ value = "(1.1 NAME 'test' DESC 'Descripton' OBSOLET )";
+ try
+ {
+ ocd = parser.parseObjectClassDescription( value );
+ fail( "Exception expected, invalid OBSOLETE value" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+ }
+
+
+ /**
+ * Test SUP and its values.
+ *
+ * @throws ParseException
+ */
+ public void testSuperior() throws ParseException
+ {
+ String value = null;
+ ObjectClassDescription ocd = null;
+
+ // no SUP
+ value = "( 1.1 )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 0, ocd.getSuperiorObjectClasses().size() );
+
+ // SUP simple numericoid
+ value = "( 1.1 SUP 1.2.3 )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 1, ocd.getSuperiorObjectClasses().size() );
+ assertEquals( "1.2.3", ocd.getSuperiorObjectClasses().get( 0 ) );
+
+ // SUP simple descr
+ value = "( 1.1 SUP top )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 1, ocd.getSuperiorObjectClasses().size() );
+ assertEquals( "top", ocd.getSuperiorObjectClasses().get( 0 ) );
+
+ // SUP single numericoid
+ value = "( 1.1 SUP ( 1.2.3.4.5 ) )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 1, ocd.getSuperiorObjectClasses().size() );
+ assertEquals( "1.2.3.4.5", ocd.getSuperiorObjectClasses().get( 0 ) );
+
+ // SUP single descr
+ value = "( 1.1 SUP ( A-Z-0-9 ) )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 1, ocd.getSuperiorObjectClasses().size() );
+ assertEquals( "A-Z-0-9", ocd.getSuperiorObjectClasses().get( 0 ) );
+
+ // SUP multi numericoid
+ value = "( 1.1 SUP ( 1.2.3 $ 1.2.3.4.5 ) )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 2, ocd.getSuperiorObjectClasses().size() );
+ assertEquals( "1.2.3", ocd.getSuperiorObjectClasses().get( 0 ) );
+ assertEquals( "1.2.3.4.5", ocd.getSuperiorObjectClasses().get( 1 ) );
+
+ // SUP multi descr
+ value = "( 1.1 SUP ( top1 $ top2 ) )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 2, ocd.getSuperiorObjectClasses().size() );
+ assertEquals( "top1", ocd.getSuperiorObjectClasses().get( 0 ) );
+ assertEquals( "top2", ocd.getSuperiorObjectClasses().get( 1 ) );
+
+ // SUP multi mixed
+ value = "( 1.1 SUP ( top1 $ 1.2.3.4 $ top2 ) )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 3, ocd.getSuperiorObjectClasses().size() );
+ assertEquals( "top1", ocd.getSuperiorObjectClasses().get( 0 ) );
+ assertEquals( "1.2.3.4", ocd.getSuperiorObjectClasses().get( 1 ) );
+ assertEquals( "top2", ocd.getSuperiorObjectClasses().get( 2 ) );
+
+ // SUP multi mixed no space
+ value = "( 1.1 SUP (TOP-1$1.2.3.4$TOP-2) )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 3, ocd.getSuperiorObjectClasses().size() );
+ assertEquals( "TOP-1", ocd.getSuperiorObjectClasses().get( 0 ) );
+ assertEquals( "1.2.3.4", ocd.getSuperiorObjectClasses().get( 1 ) );
+ assertEquals( "TOP-2", ocd.getSuperiorObjectClasses().get( 2 ) );
+
+ // SUP multi mixed many spaces
+ value = "( 1.1 SUP ( top1 $ 1.2.3.4$top2 ) )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 3, ocd.getSuperiorObjectClasses().size() );
+ assertEquals( "top1", ocd.getSuperiorObjectClasses().get( 0 ) );
+ assertEquals( "1.2.3.4", ocd.getSuperiorObjectClasses().get( 1 ) );
+ assertEquals( "top2", ocd.getSuperiorObjectClasses().get( 2 ) );
+
+ // no quote allowed
+ value = "( 1.1 SUP 'top' )";
+ try
+ {
+ ocd = parser.parseObjectClassDescription( value );
+ fail( "Exception expected, invalid SUP 'top' (quoted)" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+
+ // no quote allowed
+ value = "( 1.1 SUP '1.2.3.4' )";
+ try
+ {
+ ocd = parser.parseObjectClassDescription( value );
+ fail( "Exception expected, invalid SUP '1.2.3.4' (quoted)" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+
+ // invalid character
+ value = "( 1.1 SUP 1.2.3.4.A )";
+ try
+ {
+ ocd = parser.parseObjectClassDescription( value );
+ fail( "Exception expected, invalid SUP '1.2.3.4.A' (invalid character)" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+
+ // invalid start
+ value = "( 1.1 SUP ( top1 $ -top2 ) )";
+ try
+ {
+ ocd = parser.parseObjectClassDescription( value );
+ fail( "Exception expected, invalid SUP '-top' (starts with hypen)" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+
+ // invalid separator
+ value = "( 1.1 SUP ( top1 top2 ) )";
+ try
+ {
+ ocd = parser.parseObjectClassDescription( value );
+ fail( "Exception expected, invalid separator (no DOLLAR)" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+
+ // empty sup
+ value = "( 1.1 SUP )";
+ try
+ {
+ ocd = parser.parseObjectClassDescription( value );
+ fail( "Exception expected, no SUP value" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+ }
+
+
+ /**
+ * Tests kind (ABSTRACT, AUXILIARY, STRUCTURAL)
+ *
+ * @throws ParseException
+ */
+ public void testKind() throws ParseException
+ {
+ String value = null;
+ ObjectClassDescription ocd = null;
+
+ // DEFAULT is STRUCTURAL
+ value = "( 1.1 )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( ObjectClassDescription.Kind.STRUCTURAL, ocd.getKind() );
+
+ // ABSTRACT
+ value = "( 1.1 ABSTRACT )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( ObjectClassDescription.Kind.ABSTRACT, ocd.getKind() );
+
+ // AUXILIARY
+ value = "( 1.1 AUXILIARY )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( ObjectClassDescription.Kind.AUXILIARY, ocd.getKind() );
+
+ // STRUCTURAL
+ value = "( 1.1 STRUCTURAL )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( ObjectClassDescription.Kind.STRUCTURAL, ocd.getKind() );
+
+ // ivalid
+ value = "( 1.1 FOO )";
+ try
+ {
+ ocd = parser.parseObjectClassDescription( value );
+ fail( "Exception expected, invalid KIND value" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+ }
+
+
+ /**
+ * Test MUST and its values.
+ * Very similar to SUP, so here are less test cases.
+ *
+ * @throws ParseException
+ */
+ public void testMust() throws ParseException
+ {
+ String value = null;
+ ObjectClassDescription ocd = null;
+
+ // no MUST
+ value = "( 1.1 )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 0, ocd.getMustAttributeTypes().size() );
+
+ // MUST simple numericoid
+ value = "( 1.1 MUST 1.2.3 )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 1, ocd.getMustAttributeTypes().size() );
+ assertEquals( "1.2.3", ocd.getMustAttributeTypes().get( 0 ) );
+
+ // MUST mulitple
+ value = "(1.1 MUST (cn$sn $11.22.33.44.55 $ objectClass ))";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 4, ocd.getMustAttributeTypes().size() );
+ assertEquals( "cn", ocd.getMustAttributeTypes().get( 0 ) );
+ assertEquals( "sn", ocd.getMustAttributeTypes().get( 1 ) );
+ assertEquals( "11.22.33.44.55", ocd.getMustAttributeTypes().get( 2 ) );
+ assertEquals( "objectClass", ocd.getMustAttributeTypes().get( 3 ) );
+
+ // invalid value
+ value = "( 1.1 MUST ( c_n ) )";
+ try
+ {
+ ocd = parser.parseObjectClassDescription( value );
+ fail( "Exception expected, invalid value c_n" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+
+ // no MUST values
+ value = "( 1.1 MUST )";
+ try
+ {
+ ocd = parser.parseObjectClassDescription( value );
+ fail( "Exception expected, no MUST value" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+ }
+
+
+ /**
+ * Test MAY and its values.
+ * Very similar to SUP, so here are less test cases.
+ *
+ * @throws ParseException
+ */
+ public void testMay() throws ParseException
+ {
+ String value = null;
+ ObjectClassDescription ocd = null;
+
+ // no MAY
+ value = "( 1.1 )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 0, ocd.getMayAttributeTypes().size() );
+
+ // MAY simple numericoid
+ value = "( 1.1 MAY 1.2.3 )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 1, ocd.getMayAttributeTypes().size() );
+ assertEquals( "1.2.3", ocd.getMayAttributeTypes().get( 0 ) );
+
+ // MAY mulitple
+ value = "(1.1 MAY (cn$sn $11.22.33.44.55 $ objectClass ))";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 4, ocd.getMayAttributeTypes().size() );
+ assertEquals( "cn", ocd.getMayAttributeTypes().get( 0 ) );
+ assertEquals( "sn", ocd.getMayAttributeTypes().get( 1 ) );
+ assertEquals( "11.22.33.44.55", ocd.getMayAttributeTypes().get( 2 ) );
+ assertEquals( "objectClass", ocd.getMayAttributeTypes().get( 3 ) );
+
+ // invalid value
+ value = "( 1.1 MAY ( c_n ) )";
+ try
+ {
+ ocd = parser.parseObjectClassDescription( value );
+ fail( "Exception expected, invalid value c_n" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+ }
+
+
+ /**
+ * Test extensions.
+ *
+ * @throws ParseException
+ */
+ public void testExtensions() throws ParseException
+ {
+ String value = null;
+ ObjectClassDescription ocd = null;
+
+ // no extension
+ value = "( 1.1 )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 0, ocd.getExtensions().size() );
+
+ // single extension with one value
+ value = "( 1.1 X-TEST 'test' )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 1, ocd.getExtensions().size() );
+ assertNotNull( ocd.getExtensions().get( "X-TEST" ) );
+ assertEquals( 1, ocd.getExtensions().get( "X-TEST" ).size() );
+ assertEquals( "test", ocd.getExtensions().get( "X-TEST" ).get( 0 ) );
+
+ // single extension with multiple values
+ value = "( 1.1 X-TEST-ABC ('test1' 'test äöüÃ' 'test é¨é·' ) )";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 1, ocd.getExtensions().size() );
+ assertNotNull( ocd.getExtensions().get( "X-TEST-ABC" ) );
+ assertEquals( 3, ocd.getExtensions().get( "X-TEST-ABC" ).size() );
+ assertEquals( "test1", ocd.getExtensions().get( "X-TEST-ABC" ).get( 0 ) );
+ assertEquals( "test äöüÃ", ocd.getExtensions().get( "X-TEST-ABC" ).get( 1 ) );
+ assertEquals( "test é¨é·", ocd.getExtensions().get( "X-TEST-ABC" ).get( 2 ) );
+
+ // multiple extensions
+ value = "(1.1 X-TEST-a ('test1-1' 'test1-2') X-TEST-b ('test2-1' 'test2-2'))";
+ ocd = parser.parseObjectClassDescription( value );
+ assertEquals( 2, ocd.getExtensions().size() );
+ assertNotNull( ocd.getExtensions().get( "X-TEST-a" ) );
+ assertEquals( 2, ocd.getExtensions().get( "X-TEST-a" ).size() );
+ assertEquals( "test1-1", ocd.getExtensions().get( "X-TEST-a" ).get( 0 ) );
+ assertEquals( "test1-2", ocd.getExtensions().get( "X-TEST-a" ).get( 1 ) );
+ assertNotNull( ocd.getExtensions().get( "X-TEST-b" ) );
+ assertEquals( 2, ocd.getExtensions().get( "X-TEST-b" ).size() );
+ assertEquals( "test2-1", ocd.getExtensions().get( "X-TEST-b" ).get( 0 ) );
+ assertEquals( "test2-2", ocd.getExtensions().get( "X-TEST-b" ).get( 1 ) );
+
+ // invalid extension, no number allowed
+ value = "( 1.1 X-TEST1 'test' )";
+ try
+ {
+ ocd = parser.parseObjectClassDescription( value );
+ fail( "Exception expected, invalid extension X-TEST1 (no number allowed)" );
+ }
+ catch ( ParseException pe )
+ {
+ // expected
+ }
+
+ }
+
+
+ public void testIgnoreElementOrder() throws ParseException
+ {
+ String value = "( 2.5.6.6 STRUCTURAL MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) SUP top DESC 'RFC2256: a person' MUST ( sn $ cn ) NAME 'person' )";
+ ObjectClassDescription ocd = parser.parseObjectClassDescription( value );
+
+ assertEquals( "2.5.6.6", ocd.getNumericOid() );
+ assertEquals( 1, ocd.getNames().size() );
+ assertEquals( "person", ocd.getNames().get( 0 ) );
+ assertEquals( "RFC2256: a person", ocd.getDescription() );
+ assertEquals( 1, ocd.getSuperiorObjectClasses().size() );
+ assertEquals( "top", ocd.getSuperiorObjectClasses().get( 0 ) );
+ assertEquals( ObjectClassDescription.Kind.STRUCTURAL, ocd.getKind() );
+ assertEquals( 2, ocd.getMustAttributeTypes().size() );
+ assertEquals( "sn", ocd.getMustAttributeTypes().get( 0 ) );
+ assertEquals( "cn", ocd.getMustAttributeTypes().get( 1 ) );
+ assertEquals( 4, ocd.getMayAttributeTypes().size() );
+ assertEquals( "userPassword", ocd.getMayAttributeTypes().get( 0 ) );
+ assertEquals( "telephoneNumber", ocd.getMayAttributeTypes().get( 1 ) );
+ assertEquals( "seeAlso", ocd.getMayAttributeTypes().get( 2 ) );
+ assertEquals( "description", ocd.getMayAttributeTypes().get( 3 ) );
+ assertEquals( 0, ocd.getExtensions().size() );
+
+ }
+
+
+ ////////////////////////////////////////////////////////////////
+ // Some real-world object class definitions //
+ ////////////////////////////////////////////////////////////////
+
+ public void testRfcTop() throws ParseException
+ {
+ String value = "( 2.5.6.0 NAME 'top' DESC 'top of the superclass chain' ABSTRACT MUST objectClass )";
+ ObjectClassDescription ocd = parser.parseObjectClassDescription( value );
+
+ assertEquals( "2.5.6.0", ocd.getNumericOid() );
+ assertEquals( 1, ocd.getNames().size() );
+ assertEquals( "top", ocd.getNames().get( 0 ) );
+ assertEquals( "top of the superclass chain", ocd.getDescription() );
+ assertEquals( 0, ocd.getSuperiorObjectClasses().size() );
+ assertEquals( ObjectClassDescription.Kind.ABSTRACT, ocd.getKind() );
+ assertEquals( 1, ocd.getMustAttributeTypes().size() );
+ assertEquals( "objectClass", ocd.getMustAttributeTypes().get( 0 ) );
+ assertEquals( 0, ocd.getMayAttributeTypes().size() );
+ assertEquals( 0, ocd.getExtensions().size() );
+ }
+
+
+ public void testRfcPerson() throws ParseException
+ {
+ String value = "( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP top STRUCTURAL MUST ( sn $ cn ) MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )";
+ ObjectClassDescription ocd = parser.parseObjectClassDescription( value );
+
+ assertEquals( "2.5.6.6", ocd.getNumericOid() );
+ assertEquals( 1, ocd.getNames().size() );
+ assertEquals( "person", ocd.getNames().get( 0 ) );
+ assertEquals( "RFC2256: a person", ocd.getDescription() );
+ assertEquals( 1, ocd.getSuperiorObjectClasses().size() );
+ assertEquals( "top", ocd.getSuperiorObjectClasses().get( 0 ) );
+ assertEquals( ObjectClassDescription.Kind.STRUCTURAL, ocd.getKind() );
+ assertEquals( 2, ocd.getMustAttributeTypes().size() );
+ assertEquals( "sn", ocd.getMustAttributeTypes().get( 0 ) );
+ assertEquals( "cn", ocd.getMustAttributeTypes().get( 1 ) );
+ assertEquals( 4, ocd.getMayAttributeTypes().size() );
+ assertEquals( "userPassword", ocd.getMayAttributeTypes().get( 0 ) );
+ assertEquals( "telephoneNumber", ocd.getMayAttributeTypes().get( 1 ) );
+ assertEquals( "seeAlso", ocd.getMayAttributeTypes().get( 2 ) );
+ assertEquals( "description", ocd.getMayAttributeTypes().get( 3 ) );
+ assertEquals( 0, ocd.getExtensions().size() );
+ }
+
+
+ public void testRfcSimpleSecurityObject() throws ParseException
+ {
+ String value = "( 0.9.2342.19200300.100.4.19 NAME 'simpleSecurityObject' DESC 'RFC1274: simple security object' SUP top AUXILIARY MUST userPassword )";
+ ObjectClassDescription ocd = parser.parseObjectClassDescription( value );
+
+ assertEquals( "0.9.2342.19200300.100.4.19", ocd.getNumericOid() );
+ assertEquals( 1, ocd.getNames().size() );
+ assertEquals( "simpleSecurityObject", ocd.getNames().get( 0 ) );
+ assertEquals( "RFC1274: simple security object", ocd.getDescription() );
+ assertEquals( 1, ocd.getSuperiorObjectClasses().size() );
+ assertEquals( "top", ocd.getSuperiorObjectClasses().get( 0 ) );
+ assertEquals( ObjectClassDescription.Kind.AUXILIARY, ocd.getKind() );
+ assertEquals( 1, ocd.getMustAttributeTypes().size() );
+ assertEquals( "userPassword", ocd.getMustAttributeTypes().get( 0 ) );
+ assertEquals( 0, ocd.getMayAttributeTypes().size() );
+ assertEquals( 0, ocd.getExtensions().size() );
+ }
+
+
+ public void testSunAlias() throws ParseException
+ {
+ String value = "( 2.5.6.1 NAME 'alias' DESC 'Standard LDAP objectclass' SUP top ABSTRACT MUST aliasedObjectName X-ORIGIN 'RFC 2256' )";
+ ObjectClassDescription ocd = parser.parseObjectClassDescription( value );
+
+ assertEquals( "2.5.6.1", ocd.getNumericOid() );
+ assertEquals( 1, ocd.getNames().size() );
+ assertEquals( "alias", ocd.getNames().get( 0 ) );
+ assertEquals( "Standard LDAP objectclass", ocd.getDescription() );
+ assertEquals( 1, ocd.getSuperiorObjectClasses().size() );
+ assertEquals( "top", ocd.getSuperiorObjectClasses().get( 0 ) );
+ assertEquals( ObjectClassDescription.Kind.ABSTRACT, ocd.getKind() );
+ assertEquals( 1, ocd.getMustAttributeTypes().size() );
+ assertEquals( "aliasedObjectName", ocd.getMustAttributeTypes().get( 0 ) );
+ assertEquals( 0, ocd.getMayAttributeTypes().size() );
+
+ assertEquals( 1, ocd.getExtensions().size() );
+ assertNotNull( ocd.getExtensions().get( "X-ORIGIN" ) );
+ assertEquals( 1, ocd.getExtensions().get( "X-ORIGIN" ).size() );
+ assertEquals( "RFC 2256", ocd.getExtensions().get( "X-ORIGIN" ).get( 0 ) );
+ }
+
+
+ public void testNovellDcObject() throws ParseException
+ {
+ String value = "( 1.3.6.1.4.1.1466.344 NAME 'dcObject' AUXILIARY MUST dc X-NDS_NAMING 'dc' X-NDS_NOT_CONTAINER '1' X-NDS_NONREMOVABLE '1' )";
+ ObjectClassDescription ocd = parser.parseObjectClassDescription( value );
+
+ assertEquals( "1.3.6.1.4.1.1466.344", ocd.getNumericOid() );
+ assertEquals( 1, ocd.getNames().size() );
+ assertEquals( "dcObject", ocd.getNames().get( 0 ) );
+ assertEquals( "", ocd.getDescription() );
+ assertEquals( 0, ocd.getSuperiorObjectClasses().size() );
+ assertEquals( ObjectClassDescription.Kind.AUXILIARY, ocd.getKind() );
+ assertEquals( 1, ocd.getMustAttributeTypes().size() );
+ assertEquals( "dc", ocd.getMustAttributeTypes().get( 0 ) );
+ assertEquals( 0, ocd.getMayAttributeTypes().size() );
+
+ assertEquals( 3, ocd.getExtensions().size() );
+ assertNotNull( ocd.getExtensions().get( "X-NDS_NAMING" ) );
+ assertEquals( 1, ocd.getExtensions().get( "X-NDS_NAMING" ).size() );
+ assertEquals( "dc", ocd.getExtensions().get( "X-NDS_NAMING" ).get( 0 ) );
+ assertNotNull( ocd.getExtensions().get( "X-NDS_NOT_CONTAINER" ) );
+ assertEquals( 1, ocd.getExtensions().get( "X-NDS_NOT_CONTAINER" ).size() );
+ assertEquals( "1", ocd.getExtensions().get( "X-NDS_NOT_CONTAINER" ).get( 0 ) );
+ assertNotNull( ocd.getExtensions().get( "X-NDS_NONREMOVABLE" ) );
+ assertEquals( 1, ocd.getExtensions().get( "X-NDS_NONREMOVABLE" ).size() );
+ assertEquals( "1", ocd.getExtensions().get( "X-NDS_NONREMOVABLE" ).get( 0 ) );
+ }
+
+
+ public void testNovellList() throws ParseException
+ {
+ String value = "( 2.16.840.1.113719.1.1.6.1.30 NAME 'List' SUP Top STRUCTURAL MUST cn MAY ( description $ l $ member $ ou $ o $ eMailAddress $ mailboxLocation $ mailboxID $ owner $ seeAlso $ fullName ) X-NDS_NAMING 'cn' X-NDS_CONTAINMENT ( 'Organization' 'organizationalUnit' 'domain' ) X-NDS_NOT_CONTAINER '1' X-NDS_NONREMOVABLE '1' X-NDS_ACL_TEMPLATES '2#entry#[Root Template]#member' )";
+ ObjectClassDescription ocd = parser.parseObjectClassDescription( value );
+
+ assertEquals( "2.16.840.1.113719.1.1.6.1.30", ocd.getNumericOid() );
+ assertEquals( 1, ocd.getNames().size() );
+ assertEquals( "List", ocd.getNames().get( 0 ) );
+ assertEquals( "", ocd.getDescription() );
+ assertEquals( 1, ocd.getSuperiorObjectClasses().size() );
+ assertEquals( "Top", ocd.getSuperiorObjectClasses().get( 0 ) );
+ assertEquals( ObjectClassDescription.Kind.STRUCTURAL, ocd.getKind() );
+ assertEquals( 1, ocd.getMustAttributeTypes().size() );
+ assertEquals( "cn", ocd.getMustAttributeTypes().get( 0 ) );
+ assertEquals( 11, ocd.getMayAttributeTypes().size() );
+ assertEquals( "description", ocd.getMayAttributeTypes().get( 0 ) );
+ assertEquals( "fullName", ocd.getMayAttributeTypes().get( 10 ) );
+
+ assertEquals( 5, ocd.getExtensions().size() );
+ assertNotNull( ocd.getExtensions().get( "X-NDS_NAMING" ) );
+ assertEquals( 1, ocd.getExtensions().get( "X-NDS_NAMING" ).size() );
+ assertEquals( "cn", ocd.getExtensions().get( "X-NDS_NAMING" ).get( 0 ) );
+
+ assertNotNull( ocd.getExtensions().get( "X-NDS_NOT_CONTAINER" ) );
+ assertEquals( 1, ocd.getExtensions().get( "X-NDS_NOT_CONTAINER" ).size() );
+ assertEquals( "1", ocd.getExtensions().get( "X-NDS_NOT_CONTAINER" ).get( 0 ) );
+
+ assertNotNull( ocd.getExtensions().get( "X-NDS_NONREMOVABLE" ) );
+ assertEquals( 1, ocd.getExtensions().get( "X-NDS_NONREMOVABLE" ).size() );
+ assertEquals( "1", ocd.getExtensions().get( "X-NDS_NONREMOVABLE" ).get( 0 ) );
+
+ // X-NDS_CONTAINMENT ( 'Organization' 'organizationalUnit' 'domain' )
+ assertNotNull( ocd.getExtensions().get( "X-NDS_CONTAINMENT" ) );
+ assertEquals( 3, ocd.getExtensions().get( "X-NDS_CONTAINMENT" ).size() );
+ assertEquals( "Organization", ocd.getExtensions().get( "X-NDS_CONTAINMENT" ).get( 0 ) );
+ assertEquals( "organizationalUnit", ocd.getExtensions().get( "X-NDS_CONTAINMENT" ).get( 1 ) );
+ assertEquals( "domain", ocd.getExtensions().get( "X-NDS_CONTAINMENT" ).get( 2 ) );
+
+ // X-NDS_ACL_TEMPLATES '2#entry#[Root Template]#member'
+ assertNotNull( ocd.getExtensions().get( "X-NDS_ACL_TEMPLATES" ) );
+ assertEquals( 1, ocd.getExtensions().get( "X-NDS_ACL_TEMPLATES" ).size() );
+ assertEquals( "2#entry#[Root Template]#member", ocd.getExtensions().get( "X-NDS_ACL_TEMPLATES" ).get( 0 ) );
+ }
+
+
+ public void testMicrosoftAds2000Locality() throws ParseException
+ {
+ String value = "( 2.5.6.3 NAME 'locality' SUP top STRUCTURAL MUST (l ) MAY (st $ street $ searchGuide $ seeAlso ) )";
+ ObjectClassDescription ocd = parser.parseObjectClassDescription( value );
+
+ assertEquals( "2.5.6.3", ocd.getNumericOid() );
+ assertEquals( 1, ocd.getNames().size() );
+ assertEquals( "locality", ocd.getNames().get( 0 ) );
+ assertEquals( "", ocd.getDescription() );
+ assertEquals( 1, ocd.getSuperiorObjectClasses().size() );
+ assertEquals( "top", ocd.getSuperiorObjectClasses().get( 0 ) );
+ assertEquals( ObjectClassDescription.Kind.STRUCTURAL, ocd.getKind() );
+ assertEquals( 1, ocd.getMustAttributeTypes().size() );
+ assertEquals( "l", ocd.getMustAttributeTypes().get( 0 ) );
+ assertEquals( 4, ocd.getMayAttributeTypes().size() );
+ assertEquals( "st", ocd.getMayAttributeTypes().get( 0 ) );
+ assertEquals( "street", ocd.getMayAttributeTypes().get( 1 ) );
+ assertEquals( "searchGuide", ocd.getMayAttributeTypes().get( 2 ) );
+ assertEquals( "seeAlso", ocd.getMayAttributeTypes().get( 3 ) );
+ assertEquals( 0, ocd.getExtensions().size() );
+ }
+
+
+ public void testMicrosoftAds2003Msieee() throws ParseException
+ {
+ String value = "( 1.2.840.113556.1.5.240 NAME 'msieee80211-Policy' SUP top STRUCTURAL MAY (msieee80211-Data $ msieee80211-DataType $ msieee80211-ID ) )";
+ ObjectClassDescription ocd = parser.parseObjectClassDescription( value );
+
+ assertEquals( "1.2.840.113556.1.5.240", ocd.getNumericOid() );
+ assertEquals( 1, ocd.getNames().size() );
+ assertEquals( "msieee80211-Policy", ocd.getNames().get( 0 ) );
+ assertEquals( "", ocd.getDescription() );
+ assertEquals( 1, ocd.getSuperiorObjectClasses().size() );
+ assertEquals( "top", ocd.getSuperiorObjectClasses().get( 0 ) );
+ assertEquals( ObjectClassDescription.Kind.STRUCTURAL, ocd.getKind() );
+ assertEquals( 0, ocd.getMustAttributeTypes().size() );
+ assertEquals( 3, ocd.getMayAttributeTypes().size() );
+ assertEquals( "msieee80211-Data", ocd.getMayAttributeTypes().get( 0 ) );
+ assertEquals( "msieee80211-DataType", ocd.getMayAttributeTypes().get( 1 ) );
+ assertEquals( "msieee80211-ID", ocd.getMayAttributeTypes().get( 2 ) );
+ assertEquals( 0, ocd.getExtensions().size() );
+ }
+
+
+ public void testSiemensDirxX500Subschema() throws ParseException
+ {
+ String value = "( 2.5.20.1 NAME 'x500subSchema' AUXILIARY MAY (dITStructureRules $ nameForms $ dITContentRules $ x500objectClasses $ x500attributeTypes $ matchingRules $ matchingRuleUse) )";
+ ObjectClassDescription ocd = parser.parseObjectClassDescription( value );
+
+ assertEquals( "2.5.20.1", ocd.getNumericOid() );
+ assertEquals( 1, ocd.getNames().size() );
+ assertEquals( "x500subSchema", ocd.getNames().get( 0 ) );
+ assertEquals( "", ocd.getDescription() );
+ assertEquals( 0, ocd.getSuperiorObjectClasses().size() );
+ assertEquals( ObjectClassDescription.Kind.AUXILIARY, ocd.getKind() );
+ assertEquals( 0, ocd.getMustAttributeTypes().size() );
+ assertEquals( 7, ocd.getMayAttributeTypes().size() );
+ assertEquals( "dITStructureRules", ocd.getMayAttributeTypes().get( 0 ) );
+ assertEquals( "matchingRuleUse", ocd.getMayAttributeTypes().get( 6 ) );
+ assertEquals( 0, ocd.getExtensions().size() );
+ }
+
+
+ /**
+ * Tests the multithreaded use of a single parser.
+ */
+ public void testMultiThreaded() throws Exception
+ {
+ // start up and track all threads (40 threads)
+ List<Thread> threads = new ArrayList<Thread>();
+ for ( int ii = 0; ii < 10; ii++ )
+ {
+ Thread t0 = new Thread( new ParseSpecification( "( 1.1 )" ) );
+ Thread t1 = new Thread( new ParseSpecification(
+ "( 2.5.6.0 NAME 'top' DESC 'top of the superclass chain' ABSTRACT MUST objectClass )" ) );
+ Thread t2 = new Thread(
+ new ParseSpecification(
+ "( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP top STRUCTURAL MUST ( sn $ cn ) MAY ( userPassword $ telephoneNumber $ seeAlso $ description ) )" ) );
+ Thread t3 = new Thread(
+ new ParseSpecification(
+ "( 2.16.840.1.113719.1.1.6.1.30 NAME 'List' SUP Top STRUCTURAL MUST cn MAY ( description $ l $ member $ ou $ o $ eMailAddress $ mailboxLocation $ mailboxID $ owner $ seeAlso $ fullName ) X-NDS_NAMING 'cn' X-NDS_CONTAINMENT ( 'Organization' 'organizationalUnit' 'domain' ) X-NDS_NOT_CONTAINER '1' X-NDS_NONREMOVABLE '1' X-NDS_ACL_TEMPLATES '2#entry#[Root Template]#member' )" ) );
+ threads.add( t0 );
+ threads.add( t1 );
+ threads.add( t2 );
+ threads.add( t3 );
+ t0.start();
+ t1.start();
+ t2.start();
+ t3.start();
+ }
+
+ // wait until all threads have died
+ boolean hasLiveThreads = false;
+ do
+ {
+ hasLiveThreads = false;
+
+ for ( int ii = 0; ii < threads.size(); ii++ )
+ {
+ Thread t = ( Thread ) threads.get( ii );
+ hasLiveThreads = hasLiveThreads || t.isAlive();
+ }
+ }
+ while ( hasLiveThreads );
+
+ // check that no one thread failed to parse and generate a SS object
+ assertTrue( isSuccessMultithreaded );
+ }
+
+ /**
+ * Used to test multithreaded use of a single parser.
+ */
+ class ParseSpecification implements Runnable
+ {
+ private final String ocd;
+
+ ObjectClassDescription result;
+
+
+ public ParseSpecification( String ocd )
+ {
+ this.ocd = ocd;
+ }
+
+
+ public void run()
+ {
+ try
+ {
+ result = parser.parseObjectClassDescription( ocd );
+ }
+ catch ( ParseException e )
+ {
+ e.printStackTrace();
+ }
+
+ isSuccessMultithreaded = isSuccessMultithreaded && ( result != null );
+ }
+ }
+
+}