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 * http://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.schema.SyntaxChecker; 027import org.apache.directory.api.util.Strings; 028 029 030/** 031 * A SyntaxChecker which verifies that a value is a valid Name and Optional UID. 032 * <p> 033 * This element is a composition of two parts, a {@link Dn} and an optional UID : 034 * <pre> 035 * NameAndOptionalUID = distinguishedName [ SHARP BitString ] 036 * </pre> 037 * Both part already have their syntax checkers, so we will just call them 038 * after having split the element in two ( if necessary) 039 * <p> 040 * We just check that the {@link Dn} is valid, we don't need to verify each of the {@link Rdn} 041 * syntax. 042 * 043 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 044 */ 045@SuppressWarnings("serial") 046public final class NameAndOptionalUIDSyntaxChecker extends SyntaxChecker 047{ 048 /** 049 * A static instance of NameAndOptionalUIDSyntaxChecker 050 */ 051 public static final NameAndOptionalUIDSyntaxChecker INSTANCE = 052 new NameAndOptionalUIDSyntaxChecker( SchemaConstants.NAME_AND_OPTIONAL_UID_SYNTAX ); 053 054 /** 055 * A static Builder for this class 056 */ 057 public static final class Builder extends SCBuilder<NameAndOptionalUIDSyntaxChecker> 058 { 059 /** 060 * The Builder constructor 061 */ 062 private Builder() 063 { 064 super( SchemaConstants.NAME_AND_OPTIONAL_UID_SYNTAX ); 065 } 066 067 068 /** 069 * Create a new instance of NameAndOptionalUIDSyntaxChecker 070 * @return A new instance of NameAndOptionalUIDSyntaxChecker 071 */ 072 @Override 073 public NameAndOptionalUIDSyntaxChecker build() 074 { 075 return new NameAndOptionalUIDSyntaxChecker( oid ); 076 } 077 } 078 079 080 /** 081 * Creates a new instance of NameAndOptionalUIDSyntaxChecker. 082 * 083 * @param oid The OID to use for this SyntaxChecker 084 */ 085 private NameAndOptionalUIDSyntaxChecker( String oid ) 086 { 087 super( oid ); 088 } 089 090 091 /** 092 * @return An instance of the Builder for this class 093 */ 094 public static Builder builder() 095 { 096 return new Builder(); 097 } 098 099 100 /** 101 * {@inheritDoc} 102 */ 103 @Override 104 public boolean isValidSyntax( Object value ) 105 { 106 String strValue; 107 108 if ( value == null ) 109 { 110 if ( LOG.isDebugEnabled() ) 111 { 112 LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, "null" ) ); 113 } 114 115 return false; 116 } 117 118 if ( value instanceof String ) 119 { 120 strValue = ( String ) value; 121 } 122 else if ( value instanceof byte[] ) 123 { 124 strValue = Strings.utf8ToString( ( byte[] ) value ); 125 } 126 else 127 { 128 strValue = value.toString(); 129 } 130 131 if ( strValue.length() == 0 ) 132 { 133 if ( LOG.isDebugEnabled() ) 134 { 135 LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) ); 136 } 137 138 return false; 139 } 140 141 // Let's see if we have an UID part 142 int sharpPos = strValue.lastIndexOf( '#' ); 143 144 if ( sharpPos != -1 ) 145 { 146 // Now, check that we don't have another '#' 147 if ( strValue.indexOf( '#' ) != sharpPos ) 148 { 149 // Yes, we have one : this is not allowed, it should have been 150 // escaped. 151 if ( LOG.isDebugEnabled() ) 152 { 153 LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) ); 154 } 155 156 return false; 157 } 158 159 // This is an UID if the '#' is immediately 160 // followed by a BitString, except if the '#' is 161 // on the last position 162 if ( BitStringSyntaxChecker.isValid( strValue.substring( sharpPos + 1 ) ) 163 && ( sharpPos < strValue.length() ) ) 164 { 165 // Ok, we have a BitString, now check the Dn, 166 // except if the '#' is in first position 167 if ( sharpPos > 0 ) 168 { 169 boolean result = Dn.isValid( strValue.substring( 0, sharpPos ) ); 170 171 if ( LOG.isDebugEnabled() ) 172 { 173 if ( result ) 174 { 175 LOG.debug( I18n.msg( I18n.MSG_04489_SYNTAX_VALID, value ) ); 176 } 177 else 178 { 179 LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) ); 180 } 181 } 182 183 return result; 184 185 } 186 else 187 { 188 // The Dn must not be null ? 189 if ( LOG.isDebugEnabled() ) 190 { 191 LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) ); 192 } 193 194 return false; 195 } 196 } 197 else 198 { 199 // We have found a '#' but no UID part. 200 if ( LOG.isDebugEnabled() ) 201 { 202 LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) ); 203 } 204 205 return false; 206 } 207 } 208 else 209 { 210 // No UID, the strValue is a Dn 211 // Check that the value is a valid Dn 212 boolean result = Dn.isValid( strValue ); 213 214 if ( LOG.isDebugEnabled() ) 215 { 216 if ( result ) 217 { 218 LOG.debug( I18n.msg( I18n.MSG_04489_SYNTAX_VALID, value ) ); 219 } 220 else 221 { 222 LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) ); 223 } 224 } 225 226 return result; 227 } 228 } 229}