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 java.util.HashSet; 024import java.util.Set; 025 026import org.apache.directory.api.i18n.I18n; 027import org.apache.directory.api.ldap.model.constants.SchemaConstants; 028import org.apache.directory.api.ldap.model.schema.SyntaxChecker; 029import org.apache.directory.api.util.Chars; 030import org.apache.directory.api.util.Strings; 031 032 033/** 034 * A SyntaxChecker which verifies that a value is a delivery method 035 * according to RFC 4517. 036 * 037 * From RFC 4517 & RFC 4512: 038 * <pre> 039 * DeliveryMethod = pdm *( WSP DOLLAR WSP pdm ) 040 * 041 * pdm = "any" | "mhs" | "physical" | "telex" | "teletex" | 042 * "g3fax" | "g4fax" | "ia5" | "videotex" | "telephone" 043 * 044 * WSP = 0*SPACE ; zero or more " " 045 * DOLLAR = %x24 ; dollar sign ("$") 046 * SPACE = %x20 ; space (" ") 047 * </pre> 048 * 049 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 050 */ 051@SuppressWarnings("serial") 052public final class DeliveryMethodSyntaxChecker extends SyntaxChecker 053{ 054 private static final String[] PDMS = 055 { 056 "any", "mhs", "physical", "telex", "teletex", 057 "g3fax", "g4fax", "ia5", "videotex", "telephone" 058 }; 059 060 /** The Set which contains the delivery methods */ 061 private static final Set<String> DELIVERY_METHODS = new HashSet<>(); 062 063 /** Initialization of the delivery methods set */ 064 static 065 { 066 for ( String country : PDMS ) 067 { 068 DELIVERY_METHODS.add( country ); 069 } 070 } 071 072 /** 073 * A static instance of DeliveryMethodSyntaxChecker 074 */ 075 public static final DeliveryMethodSyntaxChecker INSTANCE = 076 new DeliveryMethodSyntaxChecker( SchemaConstants.DELIVERY_METHOD_SYNTAX ); 077 078 /** 079 * A static Builder for this class 080 */ 081 public static final class Builder extends SCBuilder<DeliveryMethodSyntaxChecker> 082 { 083 /** 084 * The Builder constructor 085 */ 086 private Builder() 087 { 088 super( SchemaConstants.DELIVERY_METHOD_SYNTAX ); 089 } 090 091 092 /** 093 * Create a new instance of DeliveryMethodSyntaxChecker 094 * @return A new instance of DeliveryMethodSyntaxChecker 095 */ 096 @Override 097 public DeliveryMethodSyntaxChecker build() 098 { 099 return new DeliveryMethodSyntaxChecker( oid ); 100 } 101 } 102 103 104 /** 105 * Creates a new instance of DeliveryMethodSyntaxChecker. 106 * 107 * @param oid The OID to use for this SyntaxChecker 108 */ 109 private DeliveryMethodSyntaxChecker( String oid ) 110 { 111 super( oid ); 112 } 113 114 115 /** 116 * @return An instance of the Builder for this class 117 */ 118 public static Builder builder() 119 { 120 return new Builder(); 121 } 122 123 124 /** 125 * 126 * Check if the string contains a delivery method which has 127 * not already been found. 128 * 129 * @param strValue The string we want to look into for a PDM 130 * @param pos The current position in the string 131 * @param pdms The set containing all the PDM 132 * @return if a Prefered Delivery Method is found in the given string, returns 133 * its position, otherwise, returns -1 134 */ 135 private int isPdm( String strValue, int start, Set<String> pdms ) 136 { 137 int pos = start; 138 139 while ( Chars.isAlphaDigit( strValue, pos ) ) 140 { 141 pos++; 142 } 143 144 // No ascii string, this is not a delivery method 145 if ( pos == start ) 146 { 147 return -1; 148 } 149 150 String pdm = strValue.substring( start, pos ); 151 152 if ( !DELIVERY_METHODS.contains( pdm ) ) 153 { 154 // The delivery method is unknown 155 return -1; 156 } 157 else 158 { 159 if ( pdms.contains( pdm ) ) 160 { 161 // The delivery method has already been found 162 return -1; 163 } 164 else 165 { 166 pdms.add( pdm ); 167 return pos; 168 } 169 } 170 } 171 172 173 /** 174 * {@inheritDoc} 175 */ 176 @Override 177 public boolean isValidSyntax( Object value ) 178 { 179 String strValue; 180 181 if ( value == null ) 182 { 183 if ( LOG.isDebugEnabled() ) 184 { 185 LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, "null" ) ); 186 } 187 188 return false; 189 } 190 191 if ( value instanceof String ) 192 { 193 strValue = ( String ) value; 194 } 195 else if ( value instanceof byte[] ) 196 { 197 strValue = Strings.utf8ToString( ( byte[] ) value ); 198 } 199 else 200 { 201 strValue = value.toString(); 202 } 203 204 if ( strValue.length() == 0 ) 205 { 206 if ( LOG.isDebugEnabled() ) 207 { 208 LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) ); 209 } 210 211 return false; 212 } 213 214 // We will get the first delivery method 215 int length = strValue.length(); 216 int pos = 0; 217 Set<String> pmds = new HashSet<>(); 218 219 pos = isPdm( strValue, pos, pmds ); 220 221 if ( pos == -1 ) 222 { 223 if ( LOG.isDebugEnabled() ) 224 { 225 LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) ); 226 } 227 228 return false; 229 } 230 231 // We have found at least the first pmd, 232 // now iterate through the other ones. We may have 233 // SP* '$' SP* before each pmd. 234 while ( pos < length ) 235 { 236 // Skip spaces 237 while ( Strings.isCharASCII( strValue, pos, ' ' ) ) 238 { 239 pos++; 240 } 241 242 if ( !Strings.isCharASCII( strValue, pos, '$' ) ) 243 { 244 // A '$' was expected 245 if ( LOG.isDebugEnabled() ) 246 { 247 LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) ); 248 } 249 250 return false; 251 } 252 else 253 { 254 pos++; 255 } 256 257 // Skip spaces 258 while ( Strings.isCharASCII( strValue, pos, ' ' ) ) 259 { 260 pos++; 261 } 262 263 pos = isPdm( strValue, pos, pmds ); 264 265 if ( pos == -1 ) 266 { 267 if ( LOG.isDebugEnabled() ) 268 { 269 LOG.debug( I18n.err( I18n.ERR_04488_SYNTAX_INVALID, value ) ); 270 } 271 272 return false; 273 } 274 } 275 276 if ( LOG.isDebugEnabled() ) 277 { 278 LOG.debug( I18n.msg( I18n.MSG_04489_SYNTAX_VALID, value ) ); 279 } 280 281 return true; 282 } 283}