| /* |
| * 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; |
| |
| |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.UUID; |
| |
| import org.apache.directory.shared.i18n.I18n; |
| import org.apache.directory.shared.ldap.constants.MetaSchemaConstants; |
| import org.apache.directory.shared.ldap.entry.Entry; |
| import org.apache.directory.shared.ldap.entry.EntryAttribute; |
| import org.apache.directory.shared.ldap.entry.Modification; |
| import org.apache.directory.shared.ldap.entry.Value; |
| import org.apache.directory.shared.ldap.exception.LdapException; |
| import org.apache.directory.shared.ldap.util.StringTools; |
| |
| |
| /** |
| * Various utility methods for schema functions and objects. |
| * |
| * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> |
| */ |
| public class SchemaUtils |
| { |
| /** |
| * Gets the target entry as it would look after a modification operation |
| * were performed on it. |
| * |
| * @param mods the modifications performed on the entry |
| * @param entry the source entry that is modified |
| * @return the resultant entry after the modifications have taken place |
| * @throws LdapException if there are problems accessing attributes |
| */ |
| public static Entry getTargetEntry( List<? extends Modification> mods, Entry entry ) |
| throws LdapException |
| { |
| Entry targetEntry = entry.clone(); |
| |
| for ( Modification mod : mods ) |
| { |
| String id = mod.getAttribute().getId(); |
| |
| switch ( mod.getOperation() ) |
| { |
| case REPLACE_ATTRIBUTE : |
| targetEntry.put( mod.getAttribute() ); |
| break; |
| |
| case ADD_ATTRIBUTE : |
| EntryAttribute combined = mod.getAttribute().clone(); |
| EntryAttribute toBeAdded = mod.getAttribute(); |
| EntryAttribute existing = entry.get( id ); |
| |
| if ( existing != null ) |
| { |
| for ( Value<?> value:existing ) |
| { |
| combined.add( value ); |
| } |
| } |
| |
| for ( Value<?> value:toBeAdded ) |
| { |
| combined.add( value ); |
| } |
| |
| targetEntry.put( combined ); |
| break; |
| |
| case REMOVE_ATTRIBUTE : |
| EntryAttribute toBeRemoved = mod.getAttribute(); |
| |
| if ( toBeRemoved.size() == 0 ) |
| { |
| targetEntry.removeAttributes( id ); |
| } |
| else |
| { |
| existing = targetEntry.get( id ); |
| |
| if ( existing != null ) |
| { |
| for ( Value<?> value:toBeRemoved ) |
| { |
| existing.remove( value ); |
| } |
| } |
| } |
| |
| break; |
| |
| default: |
| throw new IllegalStateException( I18n.err( I18n.ERR_04328, mod.getOperation() ) ); |
| } |
| } |
| |
| return targetEntry; |
| } |
| |
| |
| // ------------------------------------------------------------------------ |
| // qdescrs rendering operations |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Renders qdescrs into an existing buffer. |
| * |
| * @param buf |
| * the string buffer to render the quoted description strs into |
| * @param qdescrs |
| * the quoted description strings to render |
| * @return the same string buffer that was given for call chaining |
| */ |
| public static StringBuffer render( StringBuffer buf, List<String> qdescrs ) |
| { |
| if ( ( qdescrs == null ) || ( qdescrs.size() == 0 ) ) |
| { |
| return buf; |
| } |
| else if ( qdescrs.size() == 1 ) |
| { |
| buf.append( "'" ).append( qdescrs.get( 0 ) ).append( "'" ); |
| } |
| else |
| { |
| buf.append( "( " ); |
| |
| for ( String qdescr : qdescrs ) |
| { |
| buf.append( "'" ).append( qdescr ).append( "' " ); |
| } |
| |
| buf.append( ")" ); |
| } |
| |
| return buf; |
| } |
| |
| |
| /** |
| * Renders qdescrs into a new buffer.<br> |
| * <pre> |
| * descrs ::= qdescr | '(' WSP qdescrlist WSP ')' |
| * qdescrlist ::= [ qdescr ( SP qdescr )* ] |
| * qdescr ::= SQUOTE descr SQUOTE |
| * </pre> |
| * @param qdescrs the quoted description strings to render |
| * @return the string buffer the qdescrs are rendered into |
| */ |
| /* No qualifier */ static StringBuffer renderQDescrs( StringBuffer buf, List<String> qdescrs ) |
| { |
| if ( ( qdescrs == null ) || ( qdescrs.size() == 0 ) ) |
| { |
| return buf; |
| } |
| |
| if ( qdescrs.size() == 1 ) |
| { |
| buf.append( '\'' ).append( qdescrs.get( 0 ) ).append( '\'' ); |
| } |
| else |
| { |
| buf.append( "( " ); |
| |
| for ( String qdescr : qdescrs ) |
| { |
| buf.append( '\'' ).append( qdescr ).append( "' " ); |
| } |
| |
| buf.append( ")" ); |
| } |
| |
| return buf; |
| } |
| |
| |
| /** |
| * Renders oids into a new buffer.<br> |
| * <pre> |
| * oids ::= oid | '(' WSP oidlist WSP ')' |
| * oidlist ::= oid ( WSP '$' WSP oid )* |
| * </pre> |
| * |
| * @param qdescrs the quoted description strings to render |
| * @return the string buffer the qdescrs are rendered into |
| */ |
| private static StringBuffer renderOids( StringBuffer buf, List<String> oids ) |
| { |
| if ( oids.size() == 1 ) |
| { |
| buf.append( oids.get( 0 ) ); |
| } |
| else |
| { |
| buf.append( "( " ); |
| |
| boolean isFirst = true; |
| |
| for ( String oid : oids ) |
| { |
| if ( isFirst ) |
| { |
| isFirst = false; |
| } |
| else |
| { |
| buf.append( " $ " ); |
| } |
| |
| buf.append( oid ); |
| } |
| |
| buf.append( " )" ); |
| } |
| |
| return buf; |
| } |
| |
| |
| /** |
| * Renders QDString into a new buffer.<br> |
| * <pre> |
| * |
| * @param qdescrs the quoted description strings to render |
| * @return the string buffer the qdescrs are rendered into |
| */ |
| private static StringBuffer renderQDString( StringBuffer buf, String qdString ) |
| { |
| buf.append( '\'' ); |
| |
| for ( char c : qdString.toCharArray() ) |
| { |
| switch ( c ) |
| { |
| case 0x27 : |
| buf.append( "\\27" ); |
| break; |
| |
| case 0x5C : |
| buf.append( "\\5C" ); |
| break; |
| |
| default : |
| buf.append( c ); |
| break; |
| } |
| } |
| |
| buf.append( '\'' ); |
| |
| return buf; |
| } |
| |
| // ------------------------------------------------------------------------ |
| // objectClass list rendering operations |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Renders a list of object classes for things like a list of superior |
| * objectClasses using the ( oid $ oid ) format. |
| * |
| * @param ocs |
| * the objectClasses to list |
| * @return a buffer which contains the rendered list |
| */ |
| public static StringBuffer render( ObjectClass[] ocs ) |
| { |
| StringBuffer buf = new StringBuffer(); |
| |
| return render( buf, ocs ); |
| } |
| |
| |
| /** |
| * Renders a list of object classes for things like a list of superior |
| * objectClasses using the ( oid $ oid ) format into an existing buffer. |
| * |
| * @param buf |
| * the string buffer to render the list of objectClasses into |
| * @param ocs |
| * the objectClasses to list |
| * @return a buffer which contains the rendered list |
| */ |
| public static StringBuffer render( StringBuffer buf, ObjectClass[] ocs ) |
| { |
| if ( ocs == null || ocs.length == 0 ) |
| { |
| return buf; |
| } |
| else if ( ocs.length == 1 ) |
| { |
| buf.append( ocs[0].getName() ); |
| } |
| else |
| { |
| buf.append( "( " ); |
| |
| for ( int ii = 0; ii < ocs.length; ii++ ) |
| { |
| if ( ii + 1 < ocs.length ) |
| { |
| buf.append( ocs[ii].getName() ).append( " $ " ); |
| } |
| else |
| { |
| buf.append( ocs[ii].getName() ); |
| } |
| } |
| |
| buf.append( " )" ); |
| } |
| |
| return buf; |
| } |
| |
| |
| // ------------------------------------------------------------------------ |
| // attributeType list rendering operations |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Renders a list of attributeTypes for things like the must or may list of |
| * objectClasses using the ( oid $ oid ) format. |
| * |
| * @param ats |
| * the attributeTypes to list |
| * @return a buffer which contains the rendered list |
| */ |
| public static StringBuffer render( AttributeType[] ats ) |
| { |
| StringBuffer buf = new StringBuffer(); |
| return render( buf, ats ); |
| } |
| |
| |
| /** |
| * Renders a list of attributeTypes for things like the must or may list of |
| * objectClasses using the ( oid $ oid ) format into an existing buffer. |
| * |
| * @param buf |
| * the string buffer to render the list of attributeTypes into |
| * @param ats |
| * the attributeTypes to list |
| * @return a buffer which contains the rendered list |
| */ |
| public static StringBuffer render( StringBuffer buf, AttributeType[] ats ) |
| { |
| if ( ats == null || ats.length == 0 ) |
| { |
| return buf; |
| } |
| else if ( ats.length == 1 ) |
| { |
| buf.append( ats[0].getName() ); |
| } |
| else |
| { |
| buf.append( "( " ); |
| for ( int ii = 0; ii < ats.length; ii++ ) |
| { |
| if ( ii + 1 < ats.length ) |
| { |
| buf.append( ats[ii].getName() ).append( " $ " ); |
| } |
| else |
| { |
| buf.append( ats[ii].getName() ); |
| } |
| } |
| buf.append( " )" ); |
| } |
| |
| return buf; |
| } |
| |
| |
| // ------------------------------------------------------------------------ |
| // schema object rendering operations |
| // ------------------------------------------------------------------------ |
| |
| /** |
| * Renders an objectClass into a new StringBuffer according to the Object |
| * Class Description Syntax 1.3.6.1.4.1.1466.115.121.1.37. The syntax is |
| * described in detail within section 4.1.1. of LDAPBIS [<a |
| * href="http://ietf.org/internet-drafts/draft-ietf-ldapbis-models-12.txt">MODELS</a>] |
| * which is replicated here for convenience: |
| * |
| * <pre> |
| * 4.1.1. Object Class Definitions |
| * |
| * Object Class definitions are written according to the ABNF: |
| * |
| * 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" |
| * |
| * where: |
| * <numericoid> is object identifier assigned to this object class; |
| * NAME <qdescrs> are short names (descriptors) identifying this object |
| * class; |
| * DESC <qdstring> is a short descriptive string; |
| * OBSOLETE indicates this object class is not active; |
| * SUP <oids> specifies the direct superclasses of this object class; |
| * the kind of object class is indicated by one of ABSTRACT, |
| * STRUCTURAL, or AUXILIARY, default is STRUCTURAL; |
| * MUST and MAY specify the sets of required and allowed attribute |
| * types, respectively; and |
| * <extensions> describe extensions. |
| * </pre> |
| * @param oc the objectClass to render the description of |
| * @return the buffer containing the objectClass description |
| * @throws LdapException if there are any problems accessing objectClass |
| * information |
| */ |
| public static StringBuffer render( ObjectClass oc ) throws LdapException |
| { |
| StringBuffer buf = new StringBuffer(); |
| buf.append( "( " ).append( oc.getOid() ); |
| |
| List<String> names = oc.getNames(); |
| |
| if ( ( names != null ) && ( names.size() > 0 ) ) |
| { |
| buf.append( " NAME " ); |
| renderQDescrs( buf, names ); |
| } |
| |
| if ( oc.getDescription() != null ) |
| { |
| buf.append( " DESC " ); |
| renderQDString( buf, oc.getDescription() ); |
| } |
| |
| if ( oc.isObsolete() ) |
| { |
| buf.append( " OBSOLETE" ); |
| } |
| |
| List<String> superiorOids = oc.getSuperiorOids(); |
| |
| if ( ( superiorOids != null ) && ( superiorOids.size() > 0 ) ) |
| { |
| buf.append( " SUP " ); |
| renderOids( buf, superiorOids ); |
| } |
| |
| if ( oc.getType() != null ) |
| { |
| buf.append( " " ).append( oc.getType() ); |
| } |
| |
| List<String> must = oc.getMustAttributeTypeOids(); |
| |
| if ( ( must != null ) && ( must.size() > 0 ) ) |
| { |
| buf.append( " MUST " ); |
| renderOids( buf, must ); |
| } |
| |
| List<String> may = oc.getMayAttributeTypeOids(); |
| |
| if ( ( may != null ) && ( may.size() > 0 ) ) |
| { |
| buf.append( " MAY " ); |
| renderOids( buf, may ); |
| } |
| |
| buf.append( " X-SCHEMA '" ); |
| buf.append( oc.getSchemaName() ); |
| buf.append( "'" ); |
| |
| // @todo extensions are not presently supported and skipped |
| // the extensions would go here before closing off the description |
| |
| buf.append( " )" ); |
| |
| return buf; |
| } |
| |
| |
| /** |
| * Renders an attributeType into a new StringBuffer according to the |
| * Attribute Type Description Syntax 1.3.6.1.4.1.1466.115.121.1.3. The |
| * syntax is described in detail within section 4.1.2. of LDAPBIS [<a |
| * href="http://ietf.org/internet-drafts/draft-ietf-ldapbis-models-12.txt">MODELS</a>] |
| * which is replicated here for convenience: |
| * |
| * <pre> |
| * 4.1.2. Attribute Types |
| * |
| * Attribute Type definitions are written according to the ABNF: |
| * |
| * AttributeTypeDescription = LPAREN WSP |
| * numericoid ; object identifier |
| * [ SP "NAME" SP qdescrs ] ; short names (descriptors) |
| * [ SP "DESC" SP qdstring ] ; description |
| * [ SP "OBSOLETE" ] ; not active |
| * [ SP "SUP" SP oid ] ; supertype |
| * [ SP "EQUALITY" SP oid ] ; equality matching rule |
| * [ SP "ORDERING" SP oid ] ; ordering matching rule |
| * [ SP "SUBSTR" SP oid ] ; substrings matching rule |
| * [ SP "SYNTAX" SP noidlen ] ; value syntax |
| * [ SP "SINGLE-VALUE" ] ; single-value |
| * [ SP "COLLECTIVE" ] ; collective |
| * [ SP "NO-USER-MODIFICATION" ] ; not user modifiable |
| * [ SP "USAGE" SP usage ] ; usage |
| * extensions WSP RPAREN ; extensions |
| * |
| * usage = "userApplications" / ; user |
| * "directoryOperation" / ; directory operational |
| * "distributedOperation" / ; DSA-shared operational |
| * "dSAOperation" ; DSA-specific operational |
| * |
| * where: |
| * <numericoid> is object identifier assigned to this attribute type; |
| * NAME <qdescrs> are short names (descriptors) identifying this |
| * attribute type; |
| * DESC <qdstring> is a short descriptive string; |
| * OBSOLETE indicates this attribute type is not active; |
| * SUP oid specifies the direct supertype of this type; |
| * EQUALITY, ORDERING, SUBSTR provide the oid of the equality, |
| * ordering, and substrings matching rules, respectively; |
| * SYNTAX identifies value syntax by object identifier and may suggest |
| * a minimum upper bound; |
| * SINGLE-VALUE indicates attributes of this type are restricted to a |
| * single value; |
| * COLLECTIVE indicates this attribute type is collective |
| * [X.501][RFC3671]; |
| * NO-USER-MODIFICATION indicates this attribute type is not user |
| * modifiable; |
| * USAGE indicates the application of this attribute type; and |
| * <extensions> describe extensions. |
| * </pre> |
| * @param at the AttributeType to render the description for |
| * @return the StringBuffer containing the rendered attributeType description |
| * @throws LdapException if there are problems accessing the objects |
| * associated with the attribute type. |
| */ |
| public static StringBuffer render( AttributeType at ) throws LdapException |
| { |
| StringBuffer buf = new StringBuffer(); |
| buf.append( "( " ).append( at.getOid() ); |
| List<String> names = at.getNames(); |
| |
| if ( ( names != null ) && ( names.size() > 0 ) ) |
| { |
| buf.append( " NAME " ); |
| renderQDescrs( buf, names ); |
| } |
| |
| if ( at.getDescription() != null ) |
| { |
| buf.append( " DESC " ); |
| renderQDString( buf, at.getDescription() ); |
| } |
| |
| if ( at.isObsolete() ) |
| { |
| buf.append( " OBSOLETE" ); |
| } |
| |
| if ( at.getSuperior() != null ) |
| { |
| buf.append( " SUP " ).append( at.getSuperior().getName() ); |
| } |
| |
| if ( at.getEquality() != null ) |
| { |
| buf.append( " EQUALITY " ).append( at.getEquality().getName() ); |
| } |
| |
| if ( at.getOrdering() != null ) |
| { |
| buf.append( " ORDERING " ).append( at.getOrdering().getName() ); |
| } |
| |
| if ( at.getSubstring() != null ) |
| { |
| buf.append( " SUBSTR " ).append( at.getSubstring().getName() ); |
| } |
| |
| if ( at.getSyntax() != null ) |
| { |
| buf.append( " SYNTAX " ).append( at.getSyntax().getOid() ); |
| |
| if ( at.getSyntaxLength() > 0 ) |
| { |
| buf.append( "{" ).append( at.getSyntaxLength() ).append( "}" ); |
| } |
| } |
| |
| if ( at.isSingleValued() ) |
| { |
| buf.append( " SINGLE-VALUE" ); |
| } |
| |
| if ( at.isCollective() ) |
| { |
| buf.append( " COLLECTIVE" ); |
| } |
| |
| if ( !at.isUserModifiable() ) |
| { |
| buf.append( " NO-USER-MODIFICATION" ); |
| } |
| |
| if ( at.getUsage() != null ) |
| { |
| buf.append( " USAGE " ).append( UsageEnum.render( at.getUsage() ) ); |
| } |
| |
| buf.append( " X-SCHEMA '" ); |
| buf.append( at.getSchemaName() ); |
| buf.append( "'" ); |
| |
| // @todo extensions are not presently supported and skipped |
| // the extensions would go here before closing off the description |
| |
| buf.append( " )" ); |
| |
| return buf; |
| } |
| |
| |
| /** |
| * Renders an attributeType description object into a new StringBuffer |
| * according to the Attribute Type Description Syntax defined in MODELS |
| * 1.3.6.1.4.1.1466.115.121.1.3. The syntax is described in detail within |
| * section 4.1.2. of (@TODO NEEDS TO CHANGE SINCE THIS IS NOW AN RFC) LDAPBIS [<a |
| * href="http://ietf.org/internet-drafts/draft-ietf-ldapbis-models-12.txt">MODELS</a>] |
| * which is replicated here for convenience: |
| * |
| * <pre> |
| * 4.1.2. Attribute Types |
| * |
| * Attribute Type definitions are written according to the ABNF: |
| * |
| * AttributeTypeDescription = LPAREN WSP |
| * numericoid ; object identifier |
| * [ SP "NAME" SP qdescrs ] ; short names (descriptors) |
| * [ SP "DESC" SP qdstring ] ; description |
| * [ SP "OBSOLETE" ] ; not active |
| * [ SP "SUP" SP oid ] ; supertype |
| * [ SP "EQUALITY" SP oid ] ; equality matching rule |
| * [ SP "ORDERING" SP oid ] ; ordering matching rule |
| * [ SP "SUBSTR" SP oid ] ; substrings matching rule |
| * [ SP "SYNTAX" SP noidlen ] ; value syntax |
| * [ SP "SINGLE-VALUE" ] ; single-value |
| * [ SP "COLLECTIVE" ] ; collective |
| * [ SP "NO-USER-MODIFICATION" ] ; not user modifiable |
| * [ SP "USAGE" SP usage ] ; usage |
| * extensions WSP RPAREN ; extensions |
| * |
| * usage = "userApplications" / ; user |
| * "directoryOperation" / ; directory operational |
| * "distributedOperation" / ; DSA-shared operational |
| * "dSAOperation" ; DSA-specific operational |
| * |
| * where: |
| * <numericoid> is object identifier assigned to this attribute type; |
| * NAME <qdescrs> are short names (descriptors) identifying this |
| * attribute type; |
| * DESC <qdstring> is a short descriptive string; |
| * OBSOLETE indicates this attribute type is not active; |
| * SUP oid specifies the direct supertype of this type; |
| * EQUALITY, ORDERING, SUBSTR provide the oid of the equality, |
| * ordering, and substrings matching rules, respectively; |
| * SYNTAX identifies value syntax by object identifier and may suggest |
| * a minimum upper bound; |
| * SINGLE-VALUE indicates attributes of this type are restricted to a |
| * single value; |
| * COLLECTIVE indicates this attribute type is collective |
| * [X.501][RFC3671]; |
| * NO-USER-MODIFICATION indicates this attribute type is not user |
| * modifiable; |
| * USAGE indicates the application of this attribute type; and |
| * <extensions> describe extensions. |
| * </pre> |
| * @param attributeType the AttributeTypeDescription to render the description for |
| * @return the StringBuffer containing the rendered attributeType description |
| * @throws LdapException if there are problems accessing the objects |
| * associated with the attribute type. |
| * |
| public static StringBuffer render( AttributeType attributeType ) |
| { |
| StringBuffer buf = new StringBuffer(); |
| buf.append( "( " ).append( attributeType.getOid() ); |
| |
| if ( attributeType.getNames() != null && attributeType.getNames().size() > 0 ) |
| { |
| buf.append( " NAME " ); |
| render( buf, attributeType.getNames() ).append( " " ); |
| } |
| else |
| { |
| buf.append( " " ); |
| } |
| |
| if ( attributeType.getDescription() != null ) |
| { |
| buf.append( "DESC " ).append( "'" ).append( attributeType.getDescription() ).append( "' " ); |
| } |
| |
| if ( attributeType.isObsolete() ) |
| { |
| buf.append( " OBSOLETE" ); |
| } |
| |
| if ( attributeType.getSupOid() != null ) |
| { |
| buf.append( " SUP " ).append( attributeType.getSupOid() ); |
| } |
| |
| if ( attributeType.getEqualityOid() != null ) |
| { |
| buf.append( " EQUALITY " ).append( attributeType.getEqualityOid() ); |
| } |
| |
| if ( attributeType.getOrderingOid() != null ) |
| { |
| buf.append( " ORDERING " ).append( attributeType.getOrderingOid() ); |
| } |
| |
| if ( attributeType.getSubstrOid() != null ) |
| { |
| buf.append( " SUBSTR " ).append( attributeType.getSubstrOid() ); |
| } |
| |
| if ( attributeType.getSyntax() != null ) |
| { |
| buf.append( " SYNTAX " ).append( attributeType.getSyntax() ); |
| |
| if ( attributeType.getLength() > 0 ) |
| { |
| buf.append( "{" ).append( attributeType.getLength() ).append( "}" ); |
| } |
| } |
| |
| if ( attributeType.isSingleValue() ) |
| { |
| buf.append( " SINGLE-VALUE" ); |
| } |
| |
| if ( attributeType.isCollective() ) |
| { |
| buf.append( " COLLECTIVE" ); |
| } |
| |
| if ( !attributeType.isCanUserModify() ) |
| { |
| buf.append( " NO-USER-MODIFICATION" ); |
| } |
| |
| if ( attributeType.getUsage() != null ) |
| { |
| buf.append( " USAGE " ).append( UsageEnum.render( attributeType.getUsage() ) ); |
| } |
| |
| return buf.append( render( attributeType.getExtensions() ) ).append( ")" ); |
| } |
| |
| |
| /** |
| * Renders the schema extensions into a new StringBuffer. |
| * |
| * @param extensions the schema extensions map with key and values |
| * @return a StringBuffer with the extensions component of a syntax description |
| */ |
| public static StringBuffer render( Map<String, List<String>> extensions ) |
| { |
| StringBuffer buf = new StringBuffer(); |
| |
| if ( extensions.isEmpty() ) |
| { |
| return buf; |
| } |
| |
| for ( String key : extensions.keySet() ) |
| { |
| buf.append( " " ).append( key ).append( " " ); |
| |
| List<String> values = extensions.get( key ); |
| |
| // For extensions without values like X-IS-HUMAN-READIBLE |
| if ( values == null || values.isEmpty() ) |
| { |
| continue; |
| } |
| |
| // For extensions with a single value we can use one qdstring like 'value' |
| if ( values.size() == 1 ) |
| { |
| buf.append( "'" ).append( values.get( 0 ) ).append( "' " ); |
| continue; |
| } |
| |
| // For extensions with several values we have to surround whitespace |
| // separated list of qdstrings like ( 'value0' 'value1' 'value2' ) |
| buf.append( "( " ); |
| for ( String value : values ) |
| { |
| buf.append( "'" ).append( value ).append( "' " ); |
| } |
| buf.append( ")" ); |
| } |
| |
| if ( buf.charAt( buf.length() - 1 ) != ' ' ) |
| { |
| buf.append( " " ); |
| } |
| |
| return buf; |
| } |
| |
| |
| /** |
| * Renders an matchingRule into a new StringBuffer according to the |
| * MatchingRule Description Syntax 1.3.6.1.4.1.1466.115.121.1.30. The syntax |
| * is described in detail within section 4.1.3. of LDAPBIS [<a |
| * href="http://ietf.org/internet-drafts/draft-ietf-ldapbis-models-12.txt">MODELS</a>] |
| * which is replicated here for convenience: |
| * |
| * <pre> |
| * 4.1.3. Matching Rules |
| * |
| * Matching rules are used in performance of attribute value assertions, |
| * such as in performance of a Compare operation. They are also used in |
| * evaluation of a Search filters, in determining which individual values |
| * are be added or deleted during performance of a Modify operation, and |
| * used in comparison of distinguished names. |
| * |
| * Each matching rule is identified by an object identifier (OID) and, |
| * optionally, one or more short names (descriptors). |
| * |
| * Matching rule definitions are written according to the ABNF: |
| * |
| * MatchingRuleDescription = LPAREN WSP |
| * numericoid ; object identifier |
| * [ SP "NAME" SP qdescrs ] ; short names (descriptors) |
| * [ SP "DESC" SP qdstring ] ; description |
| * [ SP "OBSOLETE" ] ; not active |
| * SP "SYNTAX" SP numericoid ; assertion syntax |
| * extensions WSP RPAREN ; extensions |
| * |
| * where: |
| * <numericoid> is object identifier assigned to this matching rule; |
| * NAME <qdescrs> are short names (descriptors) identifying this |
| * matching rule; |
| * DESC <qdstring> is a short descriptive string; |
| * OBSOLETE indicates this matching rule is not active; |
| * SYNTAX identifies the assertion syntax (the syntax of the assertion |
| * value) by object identifier; and |
| * <extensions> describe extensions. |
| * </pre> |
| * @param mr the MatchingRule to render the description for |
| * @return the StringBuffer containing the rendered matchingRule description |
| * @throws LdapException if there are problems accessing the objects |
| * associated with the MatchingRule. |
| */ |
| public static StringBuffer render( MatchingRule mr ) throws LdapException |
| { |
| StringBuffer buf = new StringBuffer(); |
| buf.append( "( " ).append( mr.getOid() ); |
| |
| List<String> names = mr.getNames(); |
| |
| if ( ( names != null ) && ( names.size() > 0 ) ) |
| { |
| buf.append( " NAME " ); |
| renderQDescrs( buf, names ); |
| } |
| |
| if ( mr.getDescription() != null ) |
| { |
| buf.append( " DESC " ); |
| renderQDString( buf, mr.getDescription() ); |
| } |
| |
| if ( mr.isObsolete() ) |
| { |
| buf.append( " OBSOLETE" ); |
| } |
| |
| buf.append( " SYNTAX " ).append( mr.getSyntax().getOid() ); |
| |
| buf.append( " X-SCHEMA '" ); |
| buf.append( mr.getSchemaName() ); |
| buf.append( "'" ); |
| |
| // @todo extensions are not presently supported and skipped |
| // the extensions would go here before closing off the description |
| |
| buf.append( " )" ); |
| |
| return buf; |
| } |
| |
| |
| /** |
| * Renders a Syntax into a new StringBuffer according to the LDAP Syntax |
| * Description Syntax 1.3.6.1.4.1.1466.115.121.1.54. The syntax is described |
| * in detail within section 4.1.5. of LDAPBIS [<a |
| * href="http://ietf.org/internet-drafts/draft-ietf-ldapbis-models-12.txt">MODELS</a>] |
| * which is replicated here for convenience: |
| * |
| * <pre> |
| * LDAP syntax definitions are written according to the ABNF: |
| * |
| * SyntaxDescription = LPAREN WSP |
| * numericoid ; object identifier |
| * [ SP "DESC" SP qdstring ] ; description |
| * extensions WSP RPAREN ; extensions |
| * |
| * where: |
| * <numericoid> is the object identifier assigned to this LDAP syntax; |
| * DESC <qdstring> is a short descriptive string; and |
| * <extensions> describe extensions. |
| * </pre> |
| * @param syntax the Syntax to render the description for |
| * @return the StringBuffer containing the rendered syntax description |
| */ |
| public static StringBuffer render( LdapSyntax syntax ) |
| { |
| StringBuffer buf = new StringBuffer(); |
| buf.append( "( " ).append( syntax.getOid() ); |
| |
| if ( syntax.getDescription() != null ) |
| { |
| buf.append( " DESC " ); |
| renderQDString( buf, syntax.getDescription() ); |
| } |
| |
| buf.append( " X-SCHEMA '" ); |
| buf.append( syntax.getSchemaName() ); |
| |
| if ( syntax.isHumanReadable() ) |
| { |
| buf.append( "' X-IS-HUMAN-READABLE 'true'" ); |
| } |
| else |
| { |
| buf.append( "' X-IS-HUMAN-READABLE 'false'" ); |
| } |
| |
| // @todo extensions are not presently supported and skipped |
| // the extensions would go here before closing off the description |
| |
| buf.append( " )" ); |
| |
| return buf; |
| } |
| |
| |
| /** |
| * NOT FULLY IMPLEMENTED! |
| */ |
| public static StringBuffer render( MatchingRuleUse mru ) |
| { |
| StringBuffer buf = new StringBuffer(); |
| buf.append( "( " ).append( mru.getOid() ); |
| |
| List<String> names = mru.getNames(); |
| |
| if ( ( names != null ) && ( names.size() > 0 ) ) |
| { |
| buf.append( " NAME " ); |
| renderQDescrs( buf, names ); |
| } |
| |
| if ( mru.getDescription() != null ) |
| { |
| buf.append( " DESC " ); |
| renderQDString( buf, mru.getDescription() ); |
| } |
| |
| if ( mru.isObsolete ) |
| { |
| buf.append( " OBSOLETE" ); |
| } |
| |
| List<String> applies = mru.getApplicableAttributeOids(); |
| |
| if ( ( applies != null ) && ( applies.size() > 0 ) ) |
| { |
| buf.append( " APPLIES " ); |
| renderOids( buf, applies ); |
| } |
| |
| buf.append( " X-SCHEMA '" ); |
| buf.append( mru.getSchemaName() ); |
| buf.append( "'" ); |
| |
| // @todo extensions are not presently supported and skipped |
| // the extensions would go here before closing off the description |
| |
| buf.append( " )" ); |
| |
| return buf; |
| } |
| |
| |
| /** |
| * NOT FULLY IMPLEMENTED! |
| */ |
| public static StringBuffer render( DITContentRule dcr ) |
| { |
| StringBuffer buf = new StringBuffer(); |
| buf.append( "( " ).append( dcr.getOid() ); |
| |
| List<String> names = dcr.getNames(); |
| |
| if ( ( names != null ) && ( names.size() > 0 ) ) |
| { |
| buf.append( " NAME " ); |
| renderQDescrs( buf, names ); |
| } |
| |
| if ( dcr.getDescription() != null ) |
| { |
| buf.append( " DESC " ); |
| renderQDString( buf, dcr.getDescription() ); |
| } |
| |
| if ( dcr.isObsolete ) |
| { |
| buf.append( " OBSOLETE" ); |
| } |
| |
| List<String> aux = dcr.getAuxObjectClassOids(); |
| |
| if ( ( aux != null ) && ( aux.size() > 0 ) ) |
| { |
| buf.append( " AUX " ); |
| renderOids( buf, aux ); |
| } |
| |
| List<String> must = dcr.getMustAttributeTypeOids(); |
| |
| if ( ( must != null ) && ( must.size() > 0 ) ) |
| { |
| buf.append( " MUST " ); |
| renderOids( buf, must ); |
| } |
| |
| List<String> may = dcr.getMayAttributeTypeOids(); |
| |
| if ( ( may != null ) && ( may.size() > 0 ) ) |
| { |
| buf.append( " MAY " ); |
| renderOids( buf, may ); |
| } |
| |
| List<String> not = dcr.getNotAttributeTypeOids(); |
| |
| if ( ( not != null ) && ( not.size() > 0 ) ) |
| { |
| buf.append( " AUX " ); |
| renderOids( buf, not ); |
| } |
| |
| buf.append( " X-SCHEMA '" ); |
| buf.append( dcr.getSchemaName() ); |
| buf.append( "'" ); |
| |
| // @todo extensions are not presently supported and skipped |
| // the extensions would go here before closing off the description |
| |
| buf.append( " )" ); |
| |
| return buf; |
| } |
| |
| |
| /** |
| * NOT FULLY IMPLEMENTED! |
| */ |
| @SuppressWarnings("PMD.UnusedLocalVariable") // Remove me when the TODO is fixed |
| public static StringBuffer render( DITStructureRule dsr ) |
| { |
| StringBuffer buf = new StringBuffer(); |
| buf.append( "( " ).append( dsr.getOid() ); |
| |
| List<String> names = dsr.getNames(); |
| |
| if ( ( names != null ) && ( names.size() > 0 ) ) |
| { |
| buf.append( " NAME " ); |
| renderQDescrs( buf, names ); |
| } |
| |
| if ( dsr.getDescription() != null ) |
| { |
| buf.append( " DESC " ); |
| renderQDString( buf, dsr.getDescription() ); |
| } |
| |
| if ( dsr.isObsolete ) |
| { |
| buf.append( " OBSOLETE" ); |
| } |
| |
| buf.append( " FORM " ).append( dsr.getForm() ); |
| |
| List<Integer> ruleIds = dsr.getSuperRules(); |
| // TODO : Add the rendering |
| |
| buf.append( " X-SCHEMA '" ); |
| buf.append( dsr.getSchemaName() ); |
| buf.append( "' )" ); |
| |
| return buf; |
| } |
| |
| |
| /** |
| * NOT FULLY IMPLEMENTED! |
| */ |
| public static StringBuffer render( NameForm nf ) |
| { |
| StringBuffer buf = new StringBuffer(); |
| buf.append( "( " ).append( nf.getOid() ); |
| |
| List<String> names = nf.getNames(); |
| |
| if ( ( names != null ) && ( names.size() > 0 ) ) |
| { |
| buf.append( " NAME " ); |
| renderQDescrs( buf, names ); |
| } |
| |
| if ( nf.getDescription() != null ) |
| { |
| buf.append( " DESC " ); |
| renderQDString( buf, nf.getDescription() ); |
| } |
| |
| if ( nf.isObsolete ) |
| { |
| buf.append( " OBSOLETE" ); |
| } |
| |
| buf.append( " OC " ); |
| buf.append( nf.getStructuralObjectClass().getName() ); |
| |
| buf.append( " MUST " ); |
| renderOids( buf, nf.getMustAttributeTypeOids() ); |
| |
| List<String> may = nf.getMayAttributeTypeOids(); |
| |
| if ( ( may != null ) && ( may.size() > 0 ) ) |
| { |
| buf.append( " MAY " ); |
| renderOids( buf, may ); |
| } |
| |
| buf.append( " X-SCHEMA '" ); |
| buf.append( nf.getSchemaName() ); |
| buf.append( "' )" ); |
| |
| return buf; |
| } |
| |
| |
| /** |
| * Returns a String description of a schema. The resulting String format is : |
| * <br> |
| * (OID [DESC '<description>'] FQCN <fcqn> [BYTECODE <bytecode>] X-SCHEMA '<schema>') |
| * <br> |
| * @param description The description to transform to a String |
| * @return |
| */ |
| public static String render( LoadableSchemaObject description ) |
| { |
| StringBuffer buf = new StringBuffer(); |
| buf.append( "( " ).append( description.getOid() ); |
| |
| if ( description.getDescription() != null ) |
| { |
| buf.append( " DESC " ); |
| renderQDString( buf, description.getDescription() ); |
| } |
| |
| buf.append( " FQCN " ).append( description.getFqcn() ); |
| |
| if ( !StringTools.isEmpty( description.getBytecode() ) ) |
| { |
| buf.append( " BYTECODE " ).append( description.getBytecode() ); |
| } |
| |
| buf.append( " X-SCHEMA '" ); |
| buf.append( getSchemaName( description ) ); |
| buf.append( "' )" ); |
| |
| return buf.toString(); |
| } |
| |
| |
| private static String getSchemaName( SchemaObject desc ) |
| { |
| List<String> values = desc.getExtensions().get( MetaSchemaConstants.X_SCHEMA ); |
| |
| if ( values == null || values.size() == 0 ) |
| { |
| return MetaSchemaConstants.SCHEMA_OTHER; |
| } |
| |
| return values.get( 0 ); |
| } |
| |
| |
| /** |
| * Remove the options from the attributeType, and returns the ID. |
| * |
| * RFC 4512 : |
| * attributedescription = attributetype options |
| * attributetype = oid |
| * options = *( SEMI option ) |
| * option = 1*keychar |
| */ |
| public static String stripOptions( String attributeId ) |
| { |
| int optionsPos = attributeId.indexOf( ";" ); |
| |
| if ( optionsPos != -1 ) |
| { |
| return attributeId.substring( 0, optionsPos ); |
| } |
| else |
| { |
| return attributeId; |
| } |
| } |
| |
| /** |
| * Get the options from the attributeType. |
| * |
| * For instance, given : |
| * jpegphoto;binary;lang=jp |
| * |
| * your get back a set containing { "binary", "lang=jp" } |
| */ |
| public static Set<String> getOptions( String attributeId ) |
| { |
| int optionsPos = attributeId.indexOf( ";" ); |
| |
| if ( optionsPos != -1 ) |
| { |
| Set<String> options = new HashSet<String>(); |
| |
| String[] res = attributeId.substring( optionsPos + 1 ).split( ";" ); |
| |
| for ( String option:res ) |
| { |
| if ( !StringTools.isEmpty( option ) ) |
| { |
| options.add( option ); |
| } |
| } |
| |
| return options; |
| } |
| else |
| { |
| return null; |
| } |
| } |
| |
| |
| /** |
| * Transform an UUID in a byte array |
| * @param uuid The UUID to transform |
| * @return The byte[] representing the UUID |
| */ |
| public static byte[] uuidToBytes( UUID uuid ) |
| { |
| Long low = uuid.getLeastSignificantBits(); |
| Long high = uuid.getMostSignificantBits(); |
| byte[] bytes=new byte[16]; |
| |
| bytes[0] = (byte) ((high & 0xff00000000000000L)>>56); |
| bytes[1] = (byte) ((high & 0x00ff000000000000L)>>48); |
| bytes[2] = (byte) ((high & 0x0000ff0000000000L)>>40); |
| bytes[3] = (byte) ((high & 0x000000ff00000000L)>>32); |
| bytes[4] = (byte) ((high & 0x00000000ff000000L)>>24); |
| bytes[5] = (byte) ((high & 0x0000000000ff0000L)>>16); |
| bytes[6] = (byte) ((high & 0x000000000000ff00L)>>8); |
| bytes[7] = (byte) (high & 0x00000000000000ffL); |
| bytes[8] = (byte) ((low & 0xff00000000000000L)>>56); |
| bytes[9] = (byte) ((low & 0x00ff000000000000L)>>48); |
| bytes[10] = (byte) ((low & 0x0000ff0000000000L)>>40); |
| bytes[11] = (byte) ((low & 0x000000ff00000000L)>>32); |
| bytes[12] = (byte) ((low & 0x00000000ff000000L)>>24); |
| bytes[13] = (byte) ((low & 0x0000000000ff0000L)>>16); |
| bytes[14] = (byte) ((low & 0x000000000000ff00L)>>8); |
| bytes[15] = (byte) (low & 0x00000000000000ffL); |
| |
| return bytes; |
| } |
| } |