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.codec.search; 021 022 023import java.nio.BufferOverflowException; 024import java.nio.ByteBuffer; 025 026import org.apache.directory.api.asn1.EncoderException; 027import org.apache.directory.api.asn1.ber.tlv.BerValue; 028import org.apache.directory.api.asn1.ber.tlv.TLV; 029import org.apache.directory.api.i18n.I18n; 030import org.apache.directory.api.ldap.codec.api.LdapCodecConstants; 031import org.apache.directory.api.ldap.model.entry.Value; 032import org.apache.directory.api.util.Strings; 033 034 035/** 036 * The search request filter Matching Rule assertion 037 * 038 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 039 */ 040public class ExtensibleMatchFilter extends Filter 041{ 042 /** The expected lenth of the Matching Rule Assertion */ 043 private int expectedMatchingRuleLength; 044 045 /** Matching rule */ 046 private String matchingRule; 047 048 /** Matching rule bytes */ 049 private byte[] matchingRuleBytes; 050 051 /** Matching rule type */ 052 private String type; 053 054 private byte[] typeBytes; 055 056 /** Matching rule value */ 057 private Value matchValue; 058 059 /** The dnAttributes flag */ 060 private boolean dnAttributes = false; 061 062 /** The extensible match length */ 063 private int extensibleMatchLength; 064 065 066 /** 067 * Creates a new ExtensibleMatchFilter object. The dnAttributes flag 068 * defaults to false. 069 * 070 * @param tlvId The TLV identifier 071 */ 072 public ExtensibleMatchFilter( int tlvId ) 073 { 074 super( tlvId ); 075 } 076 077 078 /** 079 * Creates a new ExtensibleMatchFilter object. The dnAttributes flag 080 * defaults to false. 081 */ 082 public ExtensibleMatchFilter() 083 { 084 super(); 085 } 086 087 088 /** 089 * Get the dnAttributes flag 090 * 091 * @return Returns the dnAttributes. 092 */ 093 public boolean isDnAttributes() 094 { 095 return dnAttributes; 096 } 097 098 099 /** 100 * Set the dnAttributes flag 101 * 102 * @param dnAttributes The dnAttributes to set. 103 */ 104 public void setDnAttributes( boolean dnAttributes ) 105 { 106 this.dnAttributes = dnAttributes; 107 } 108 109 110 /** 111 * Get the matchingRule 112 * 113 * @return Returns the matchingRule. 114 */ 115 public String getMatchingRule() 116 { 117 return matchingRule; 118 } 119 120 121 /** 122 * Set the matchingRule 123 * 124 * @param matchingRule The matchingRule to set. 125 */ 126 public void setMatchingRule( String matchingRule ) 127 { 128 this.matchingRule = matchingRule; 129 } 130 131 132 /** 133 * Get the matchValue 134 * 135 * @return Returns the matchValue. 136 */ 137 public Value getMatchValue() 138 { 139 return matchValue; 140 } 141 142 143 /** 144 * Set the matchValue 145 * 146 * @param matchValue The matchValue to set. 147 */ 148 public void setMatchValue( Value matchValue ) 149 { 150 this.matchValue = matchValue; 151 } 152 153 154 /** 155 * Get the type 156 * 157 * @return Returns the type. 158 */ 159 public String getType() 160 { 161 return type; 162 } 163 164 165 /** 166 * Set the type 167 * 168 * @param type The type to set. 169 */ 170 public void setType( String type ) 171 { 172 this.type = type; 173 } 174 175 176 /** 177 * get the expectedMatchingRuleLength 178 * 179 * @return Returns the expectedMatchingRuleLength. 180 */ 181 public int getExpectedMatchingRuleLength() 182 { 183 return expectedMatchingRuleLength; 184 } 185 186 187 /** 188 * Set the expectedMatchingRuleLength 189 * 190 * @param expectedMatchingRuleLength The expectedMatchingRuleLength to set. 191 */ 192 public void setExpectedMatchingRuleLength( int expectedMatchingRuleLength ) 193 { 194 this.expectedMatchingRuleLength = expectedMatchingRuleLength; 195 } 196 197 198 /** 199 * Compute the ExtensibleMatchFilter length 200 * <br> 201 * ExtensibleMatchFilter : 202 * <pre> 203 * 0xA9 L1 204 * | 205 * [+--> 0x81 L3 matchingRule] 206 * [+--> 0x82 L4 type] 207 * [+--> 0x83 L5 matchValue] 208 * [+--> 0x01 0x01 dnAttributes] 209 * </pre> 210 * 211 * @return The encoded length 212 */ 213 @Override 214 public int computeLength() 215 { 216 if ( matchingRule != null ) 217 { 218 matchingRuleBytes = Strings.getBytesUtf8( matchingRule ); 219 extensibleMatchLength = 1 + TLV.getNbBytes( matchingRuleBytes.length ) + matchingRuleBytes.length; 220 } 221 222 if ( type != null ) 223 { 224 typeBytes = Strings.getBytesUtf8( type ); 225 extensibleMatchLength += 1 + TLV.getNbBytes( typeBytes.length ) + typeBytes.length; 226 } 227 228 if ( matchValue != null ) 229 { 230 int bytesLength = matchValue.getBytes().length; 231 extensibleMatchLength += 1 + TLV.getNbBytes( bytesLength ) + bytesLength; 232 } 233 234 if ( dnAttributes ) 235 { 236 extensibleMatchLength += 1 + 1 + 1; 237 } 238 239 return 1 + TLV.getNbBytes( extensibleMatchLength ) + extensibleMatchLength; 240 } 241 242 243 /** 244 * Encode the ExtensibleMatch Filters to a PDU. 245 * <br> 246 * ExtensibleMatch filter : 247 * <pre> 248 * 0xA9 LL 249 * | 0x81 LL matchingRule 250 * | / | 0x82 LL Type 251 * | / | /0x83 LL matchValue 252 * +--+ +-+ 253 * | \ \ 254 * | \ 0x83 LL MatchValue 255 * | 0x82 LL type 256 * | 0x83 LL matchValue 257 * +--[0x84 0x01 dnAttributes] 258 * </pre> 259 * 260 * @param buffer The buffer where to put the PDU 261 * @return The PDU. 262 */ 263 @Override 264 public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException 265 { 266 if ( buffer == null ) 267 { 268 throw new EncoderException( I18n.err( I18n.ERR_08000_CANNOT_PUT_A_PDU_IN_NULL_BUFFER ) ); 269 } 270 271 try 272 { 273 // The ExtensibleMatch Tag 274 buffer.put( ( byte ) LdapCodecConstants.EXTENSIBLE_MATCH_FILTER_TAG ); 275 buffer.put( TLV.getBytes( extensibleMatchLength ) ); 276 277 if ( ( matchingRule == null ) && ( type == null ) ) 278 { 279 throw new EncoderException( I18n.err( I18n.ERR_05500_NULL_MATCHING_RULE_AND_TYPE ) ); 280 } 281 282 // The matching rule 283 if ( matchingRule != null ) 284 { 285 buffer.put( ( byte ) LdapCodecConstants.MATCHING_RULE_ID_TAG ); 286 buffer.put( TLV.getBytes( matchingRuleBytes.length ) ); 287 buffer.put( matchingRuleBytes ); 288 } 289 290 // The type 291 if ( type != null ) 292 { 293 buffer.put( ( byte ) LdapCodecConstants.MATCHING_RULE_TYPE_TAG ); 294 buffer.put( TLV.getBytes( typeBytes.length ) ); 295 buffer.put( typeBytes ); 296 } 297 298 // The match value 299 if ( matchValue != null ) 300 { 301 buffer.put( ( byte ) LdapCodecConstants.MATCH_VALUE_TAG ); 302 303 byte[] bytes = matchValue.getBytes(); 304 int bytesLength = bytes.length; 305 buffer.put( TLV.getBytes( bytesLength ) ); 306 307 if ( bytesLength != 0 ) 308 { 309 buffer.put( bytes ); 310 } 311 312 } 313 314 // The dnAttributes flag, if true only 315 if ( dnAttributes ) 316 { 317 buffer.put( ( byte ) LdapCodecConstants.DN_ATTRIBUTES_FILTER_TAG ); 318 buffer.put( ( byte ) 1 ); 319 buffer.put( BerValue.TRUE_VALUE ); 320 } 321 } 322 catch ( BufferOverflowException boe ) 323 { 324 throw new EncoderException( I18n.err( I18n.ERR_08212_PDU_BUFFER_TOO_SMALL ), boe ); 325 } 326 327 return buffer; 328 } 329 330 331 /** 332 * Return a String representing an extended filter as of RFC 2254 333 * 334 * @return An Extended Filter String 335 */ 336 @Override 337 public String toString() 338 { 339 340 StringBuilder sb = new StringBuilder(); 341 342 if ( type != null ) 343 { 344 sb.append( type ); 345 } 346 347 if ( dnAttributes ) 348 { 349 sb.append( ":dn" ); 350 } 351 352 if ( matchingRule == null ) 353 { 354 355 if ( type == null ) 356 { 357 return "Extended Filter wrong syntax"; 358 } 359 } 360 else 361 { 362 sb.append( ':' ).append( matchingRule ); 363 } 364 365 sb.append( ":=" ).append( matchValue ); 366 367 return sb.toString(); 368 } 369}