001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020package org.apache.directory.api.ldap.model.schema.syntaxCheckers; 021 022 023import org.apache.directory.api.i18n.I18n; 024import org.apache.directory.api.ldap.model.constants.SchemaConstants; 025import org.apache.directory.api.ldap.model.name.Dn; 026import org.apache.directory.api.ldap.model.name.Rdn; 027import org.apache.directory.api.ldap.model.schema.SyntaxChecker; 028import org.apache.directory.api.util.Strings; 029 030 031/** 032 * A SyntaxChecker which verifies that a value is a valid Name and Optional UID. 033 * <p> 034 * This element is a composition of two parts, a {@link Dn} and an optional UID : 035 * <pre> 036 * NameAndOptionalUID = distinguishedName [ SHARP BitString ] 037 * </pre> 038 * Both part already have their syntax checkers, so we will just call them 039 * after having split the element in two ( if necessary) 040 * <p> 041 * We just check that the {@link Dn} is valid, we don't need to verify each of the {@link Rdn} 042 * syntax. 043 * 044 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 045 */ 046@SuppressWarnings("serial") 047public final class NameAndOptionalUIDSyntaxChecker extends SyntaxChecker 048{ 049 /** 050 * A static instance of NameAndOptionalUIDSyntaxChecker 051 */ 052 public static final NameAndOptionalUIDSyntaxChecker INSTANCE = 053 new NameAndOptionalUIDSyntaxChecker( SchemaConstants.NAME_AND_OPTIONAL_UID_SYNTAX ); 054 055 /** 056 * A static Builder for this class 057 */ 058 public static final class Builder extends SCBuilder<NameAndOptionalUIDSyntaxChecker> 059 { 060 /** 061 * The Builder constructor 062 */ 063 private Builder() 064 { 065 super( SchemaConstants.NAME_AND_OPTIONAL_UID_SYNTAX ); 066 } 067 068 069 /** 070 * Create a new instance of NameAndOptionalUIDSyntaxChecker 071 * @return A new instance of NameAndOptionalUIDSyntaxChecker 072 */ 073 @Override 074 public NameAndOptionalUIDSyntaxChecker build() 075 { 076 return new NameAndOptionalUIDSyntaxChecker( oid ); 077 } 078 } 079 080 081 /** 082 * Creates a new instance of NameAndOptionalUIDSyntaxChecker. 083 * 084 * @param oid The OID to use for this SyntaxChecker 085 */ 086 private NameAndOptionalUIDSyntaxChecker( String oid ) 087 { 088 super( oid ); 089 } 090 091 092 /** 093 * @return An instance of the Builder for this class 094 */ 095 public static Builder builder() 096 { 097 return new Builder(); 098 } 099 100 101 /** 102 * {@inheritDoc} 103 */ 104 @Override 105 public boolean isValidSyntax( Object value ) 106 { 107 String strValue; 108 109 if ( value == null ) 110 { 111 if ( LOG.isDebugEnabled() ) 112 { 113 LOG.debug( I18n.err( I18n.ERR_13210_SYNTAX_INVALID, "null" ) ); 114 } 115 116 return false; 117 } 118 119 if ( value instanceof String ) 120 { 121 strValue = ( String ) value; 122 } 123 else if ( value instanceof byte[] ) 124 { 125 strValue = Strings.utf8ToString( ( byte[] ) value ); 126 } 127 else 128 { 129 strValue = value.toString(); 130 } 131 132 if ( strValue.length() == 0 ) 133 { 134 if ( LOG.isDebugEnabled() ) 135 { 136 LOG.debug( I18n.err( I18n.ERR_13210_SYNTAX_INVALID, value ) ); 137 } 138 139 return false; 140 } 141 142 // Let's see if we have an UID part 143 int sharpPos = strValue.lastIndexOf( '#' ); 144 145 if ( sharpPos != -1 ) 146 { 147 // Now, check that we don't have another '#' 148 if ( strValue.indexOf( '#' ) != sharpPos ) 149 { 150 // Yes, we have one : this is not allowed, it should have been 151 // escaped. 152 if ( LOG.isDebugEnabled() ) 153 { 154 LOG.debug( I18n.err( I18n.ERR_13210_SYNTAX_INVALID, value ) ); 155 } 156 157 return false; 158 } 159 160 // This is an UID if the '#' is immediately 161 // followed by a BitString, except if the '#' is 162 // on the last position 163 if ( BitStringSyntaxChecker.isValid( strValue.substring( sharpPos + 1 ) ) 164 && ( sharpPos < strValue.length() ) ) 165 { 166 // Ok, we have a BitString, now check the Dn, 167 // except if the '#' is in first position 168 if ( sharpPos > 0 ) 169 { 170 boolean result = Dn.isValid( strValue.substring( 0, sharpPos ) ); 171 172 if ( LOG.isDebugEnabled() ) 173 { 174 if ( result ) 175 { 176 LOG.debug( I18n.msg( I18n.MSG_13701_SYNTAX_VALID, value ) ); 177 } 178 else 179 { 180 LOG.debug( I18n.err( I18n.ERR_13210_SYNTAX_INVALID, value ) ); 181 } 182 } 183 184 return result; 185 186 } 187 else 188 { 189 // The Dn must not be null ? 190 if ( LOG.isDebugEnabled() ) 191 { 192 LOG.debug( I18n.err( I18n.ERR_13210_SYNTAX_INVALID, value ) ); 193 } 194 195 return false; 196 } 197 } 198 else 199 { 200 // We have found a '#' but no UID part. 201 if ( LOG.isDebugEnabled() ) 202 { 203 LOG.debug( I18n.err( I18n.ERR_13210_SYNTAX_INVALID, value ) ); 204 } 205 206 return false; 207 } 208 } 209 else 210 { 211 // No UID, the strValue is a Dn 212 // Check that the value is a valid Dn 213 boolean result = Dn.isValid( strValue ); 214 215 if ( LOG.isDebugEnabled() ) 216 { 217 if ( result ) 218 { 219 LOG.debug( I18n.msg( I18n.MSG_13701_SYNTAX_VALID, value ) ); 220 } 221 else 222 { 223 LOG.debug( I18n.err( I18n.ERR_13210_SYNTAX_INVALID, value ) ); 224 } 225 } 226 227 return result; 228 } 229 } 230}